summaryrefslogtreecommitdiffstats
path: root/sys/crypto/aesni/aesni_wrap.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-07-23 11:00:46 +0000
committerkib <kib@FreeBSD.org>2010-07-23 11:00:46 +0000
commita6198465870ecad0428d823988838d909c1b779b (patch)
treefe15b0b26d50bcebdbb695bd94b9843d3c224d2d /sys/crypto/aesni/aesni_wrap.c
parentfe775469770ee94612fdad1e2fedc4f12deb6ba3 (diff)
downloadFreeBSD-src-a6198465870ecad0428d823988838d909c1b779b.zip
FreeBSD-src-a6198465870ecad0428d823988838d909c1b779b.tar.gz
Crypto(4) driver for AESNI.
The aeskeys_{amd64,i386}.S content was mostly obtained from OpenBSD, no objections to the license from core. Hardware provided by: Sentex Communications Tested by: fabient, pho (previous versions) MFC after: 1 month
Diffstat (limited to 'sys/crypto/aesni/aesni_wrap.c')
-rw-r--r--sys/crypto/aesni/aesni_wrap.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/sys/crypto/aesni/aesni_wrap.c b/sys/crypto/aesni/aesni_wrap.c
new file mode 100644
index 0000000..fd08222
--- /dev/null
+++ b/sys/crypto/aesni/aesni_wrap.c
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 2010 Konstantin Belousov <kib@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/libkern.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <crypto/aesni/aesni.h>
+
+MALLOC_DECLARE(M_AESNI);
+
+#ifdef DEBUG
+static void
+ps_len(const char *string, const uint8_t *data, int length)
+{
+ int i;
+
+ printf("%-12s[0x", string);
+ for(i = 0; i < length; i++) {
+ if (i % AES_BLOCK_LEN == 0 && i > 0)
+ printf("+");
+ printf("%02x", data[i]);
+ }
+ printf("]\n");
+}
+#endif
+
+void
+aesni_encrypt_cbc(int rounds, const void *key_schedule, size_t len,
+ const uint8_t *from, uint8_t *to, const uint8_t iv[AES_BLOCK_LEN])
+{
+ const uint8_t *ivp;
+ size_t i;
+
+#ifdef DEBUG
+ ps_len("AES CBC encrypt iv:", iv, AES_BLOCK_LEN);
+ ps_len("from:", from, len);
+#endif
+
+ len /= AES_BLOCK_LEN;
+ ivp = iv;
+ for (i = 0; i < len; i++) {
+ aesni_enc(rounds - 1, key_schedule, from, to, ivp);
+ ivp = to;
+ from += AES_BLOCK_LEN;
+ to += AES_BLOCK_LEN;
+ }
+#ifdef DEBUG
+ ps_len("to:", to - len * AES_BLOCK_LEN, len * AES_BLOCK_LEN);
+#endif
+}
+
+void
+aesni_encrypt_ecb(int rounds, const void *key_schedule, size_t len,
+ const uint8_t from[AES_BLOCK_LEN], uint8_t to[AES_BLOCK_LEN])
+{
+ size_t i;
+
+ len /= AES_BLOCK_LEN;
+ for (i = 0; i < len; i++) {
+ aesni_enc(rounds - 1, key_schedule, from, to, NULL);
+ from += AES_BLOCK_LEN;
+ to += AES_BLOCK_LEN;
+ }
+}
+
+void
+aesni_decrypt_ecb(int rounds, const void *key_schedule, size_t len,
+ const uint8_t from[AES_BLOCK_LEN], uint8_t to[AES_BLOCK_LEN])
+{
+ size_t i;
+
+ len /= AES_BLOCK_LEN;
+ for (i = 0; i < len; i++) {
+ aesni_dec(rounds - 1, key_schedule, from, to, NULL);
+ from += AES_BLOCK_LEN;
+ to += AES_BLOCK_LEN;
+ }
+}
+
+int
+aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini)
+{
+ struct thread *td;
+ int error;
+
+ switch (encini->cri_klen) {
+ case 128:
+ ses->rounds = AES128_ROUNDS;
+ break;
+ case 192:
+ ses->rounds = AES192_ROUNDS;
+ break;
+ case 256:
+ ses->rounds = AES256_ROUNDS;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ td = curthread;
+ error = fpu_kern_enter(td, &ses->fpu_ctx, FPU_KERN_NORMAL);
+ if (error == 0) {
+ aesni_set_enckey(encini->cri_key, ses->enc_schedule,
+ ses->rounds);
+ aesni_set_deckey(ses->enc_schedule, ses->dec_schedule,
+ ses->rounds);
+ arc4rand(ses->iv, sizeof(ses->iv), 0);
+ fpu_kern_leave(td, &ses->fpu_ctx);
+ }
+ return (error);
+}
+
+int
+aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd,
+ struct cryptop *crp)
+{
+ struct thread *td;
+ uint8_t *buf;
+ int error, allocated;
+
+ buf = aesni_cipher_alloc(enccrd, crp, &allocated);
+ if (buf == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ td = curthread;
+ error = fpu_kern_enter(td, &ses->fpu_ctx, FPU_KERN_NORMAL);
+ if (error != 0)
+ goto out1;
+
+ if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) {
+ if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
+ bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN);
+
+ if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0)
+ crypto_copyback(crp->crp_flags, crp->crp_buf,
+ enccrd->crd_inject, AES_BLOCK_LEN, ses->iv);
+
+ aesni_encrypt_cbc(ses->rounds, ses->enc_schedule,
+ enccrd->crd_len, buf, buf, ses->iv);
+ } else {
+ if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
+ bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN);
+ else
+ crypto_copydata(crp->crp_flags, crp->crp_buf,
+ enccrd->crd_inject, AES_BLOCK_LEN, ses->iv);
+ aesni_decrypt_cbc(ses->rounds, ses->dec_schedule,
+ enccrd->crd_len, buf, ses->iv);
+ }
+ fpu_kern_leave(td, &ses->fpu_ctx);
+ if (allocated)
+ crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
+ enccrd->crd_len, buf);
+ if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0)
+ crypto_copydata(crp->crp_flags, crp->crp_buf,
+ enccrd->crd_skip + enccrd->crd_len - AES_BLOCK_LEN,
+ AES_BLOCK_LEN, ses->iv);
+ out1:
+ if (allocated) {
+ bzero(buf, enccrd->crd_len);
+ free(buf, M_AESNI);
+ }
+ out:
+ return (error);
+}
OpenPOWER on IntegriCloud