aesni_wrap.c revision 210409
1210409Skib/*-
2210409Skib * Copyright (c) 2010 Konstantin Belousov <kib@FreeBSD.org>
3210409Skib * All rights reserved.
4210409Skib *
5210409Skib * Redistribution and use in source and binary forms, with or without
6210409Skib * modification, are permitted provided that the following conditions
7210409Skib * are met:
8210409Skib * 1. Redistributions of source code must retain the above copyright
9210409Skib *    notice, this list of conditions and the following disclaimer.
10210409Skib * 2. Redistributions in binary form must reproduce the above copyright
11210409Skib *    notice, this list of conditions and the following disclaimer in the
12210409Skib *    documentation and/or other materials provided with the distribution.
13210409Skib *
14210409Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15210409Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16210409Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210409Skib * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18210409Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19210409Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20210409Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21210409Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210409Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210409Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210409Skib * SUCH DAMAGE.
25210409Skib */
26210409Skib
27210409Skib#include <sys/cdefs.h>
28210409Skib__FBSDID("$FreeBSD: head/sys/crypto/aesni/aesni_wrap.c 210409 2010-07-23 11:00:46Z kib $");
29210409Skib
30210409Skib#include <sys/param.h>
31210409Skib#include <sys/libkern.h>
32210409Skib#include <sys/malloc.h>
33210409Skib#include <sys/proc.h>
34210409Skib#include <sys/systm.h>
35210409Skib#include <crypto/aesni/aesni.h>
36210409Skib
37210409SkibMALLOC_DECLARE(M_AESNI);
38210409Skib
39210409Skib#ifdef DEBUG
40210409Skibstatic void
41210409Skibps_len(const char *string, const uint8_t *data, int length)
42210409Skib{
43210409Skib	int i;
44210409Skib
45210409Skib	printf("%-12s[0x", string);
46210409Skib	for(i = 0; i < length; i++) {
47210409Skib		if (i % AES_BLOCK_LEN == 0 && i > 0)
48210409Skib			printf("+");
49210409Skib		printf("%02x", data[i]);
50210409Skib	}
51210409Skib	printf("]\n");
52210409Skib}
53210409Skib#endif
54210409Skib
55210409Skibvoid
56210409Skibaesni_encrypt_cbc(int rounds, const void *key_schedule, size_t len,
57210409Skib    const uint8_t *from, uint8_t *to, const uint8_t iv[AES_BLOCK_LEN])
58210409Skib{
59210409Skib	const uint8_t *ivp;
60210409Skib	size_t i;
61210409Skib
62210409Skib#ifdef DEBUG
63210409Skib	ps_len("AES CBC encrypt iv:", iv, AES_BLOCK_LEN);
64210409Skib	ps_len("from:", from, len);
65210409Skib#endif
66210409Skib
67210409Skib	len /= AES_BLOCK_LEN;
68210409Skib	ivp = iv;
69210409Skib	for (i = 0; i < len; i++) {
70210409Skib		aesni_enc(rounds - 1, key_schedule, from, to, ivp);
71210409Skib		ivp = to;
72210409Skib		from += AES_BLOCK_LEN;
73210409Skib		to += AES_BLOCK_LEN;
74210409Skib	}
75210409Skib#ifdef DEBUG
76210409Skib	ps_len("to:", to - len * AES_BLOCK_LEN, len * AES_BLOCK_LEN);
77210409Skib#endif
78210409Skib}
79210409Skib
80210409Skibvoid
81210409Skibaesni_encrypt_ecb(int rounds, const void *key_schedule, size_t len,
82210409Skib    const uint8_t from[AES_BLOCK_LEN], uint8_t to[AES_BLOCK_LEN])
83210409Skib{
84210409Skib	size_t i;
85210409Skib
86210409Skib	len /= AES_BLOCK_LEN;
87210409Skib	for (i = 0; i < len; i++) {
88210409Skib		aesni_enc(rounds - 1, key_schedule, from, to, NULL);
89210409Skib		from += AES_BLOCK_LEN;
90210409Skib		to += AES_BLOCK_LEN;
91210409Skib	}
92210409Skib}
93210409Skib
94210409Skibvoid
95210409Skibaesni_decrypt_ecb(int rounds, const void *key_schedule, size_t len,
96210409Skib    const uint8_t from[AES_BLOCK_LEN], uint8_t to[AES_BLOCK_LEN])
97210409Skib{
98210409Skib	size_t i;
99210409Skib
100210409Skib	len /= AES_BLOCK_LEN;
101210409Skib	for (i = 0; i < len; i++) {
102210409Skib		aesni_dec(rounds - 1, key_schedule, from, to, NULL);
103210409Skib		from += AES_BLOCK_LEN;
104210409Skib		to += AES_BLOCK_LEN;
105210409Skib	}
106210409Skib}
107210409Skib
108210409Skibint
109210409Skibaesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini)
110210409Skib{
111210409Skib	struct thread *td;
112210409Skib	int error;
113210409Skib
114210409Skib	switch (encini->cri_klen) {
115210409Skib	case 128:
116210409Skib		ses->rounds = AES128_ROUNDS;
117210409Skib		break;
118210409Skib	case 192:
119210409Skib		ses->rounds = AES192_ROUNDS;
120210409Skib		break;
121210409Skib	case 256:
122210409Skib		ses->rounds = AES256_ROUNDS;
123210409Skib		break;
124210409Skib	default:
125210409Skib		return (EINVAL);
126210409Skib	}
127210409Skib
128210409Skib	td = curthread;
129210409Skib	error = fpu_kern_enter(td, &ses->fpu_ctx, FPU_KERN_NORMAL);
130210409Skib	if (error == 0) {
131210409Skib		aesni_set_enckey(encini->cri_key, ses->enc_schedule,
132210409Skib		    ses->rounds);
133210409Skib		aesni_set_deckey(ses->enc_schedule, ses->dec_schedule,
134210409Skib		    ses->rounds);
135210409Skib		arc4rand(ses->iv, sizeof(ses->iv), 0);
136210409Skib		fpu_kern_leave(td, &ses->fpu_ctx);
137210409Skib	}
138210409Skib	return (error);
139210409Skib}
140210409Skib
141210409Skibint
142210409Skibaesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd,
143210409Skib    struct cryptop *crp)
144210409Skib{
145210409Skib	struct thread *td;
146210409Skib	uint8_t *buf;
147210409Skib	int error, allocated;
148210409Skib
149210409Skib	buf = aesni_cipher_alloc(enccrd, crp, &allocated);
150210409Skib	if (buf == NULL) {
151210409Skib		error = ENOMEM;
152210409Skib		goto out;
153210409Skib	}
154210409Skib
155210409Skib	td = curthread;
156210409Skib	error = fpu_kern_enter(td, &ses->fpu_ctx, FPU_KERN_NORMAL);
157210409Skib	if (error != 0)
158210409Skib		goto out1;
159210409Skib
160210409Skib	if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) {
161210409Skib		if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
162210409Skib			bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN);
163210409Skib
164210409Skib		if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0)
165210409Skib			crypto_copyback(crp->crp_flags, crp->crp_buf,
166210409Skib			    enccrd->crd_inject, AES_BLOCK_LEN, ses->iv);
167210409Skib
168210409Skib		aesni_encrypt_cbc(ses->rounds, ses->enc_schedule,
169210409Skib		    enccrd->crd_len, buf, buf, ses->iv);
170210409Skib	} else {
171210409Skib		if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
172210409Skib			bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN);
173210409Skib		else
174210409Skib			crypto_copydata(crp->crp_flags, crp->crp_buf,
175210409Skib			    enccrd->crd_inject, AES_BLOCK_LEN, ses->iv);
176210409Skib		aesni_decrypt_cbc(ses->rounds, ses->dec_schedule,
177210409Skib		    enccrd->crd_len, buf, ses->iv);
178210409Skib	}
179210409Skib	fpu_kern_leave(td, &ses->fpu_ctx);
180210409Skib	if (allocated)
181210409Skib		crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
182210409Skib		    enccrd->crd_len, buf);
183210409Skib	if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0)
184210409Skib		crypto_copydata(crp->crp_flags, crp->crp_buf,
185210409Skib		    enccrd->crd_skip + enccrd->crd_len - AES_BLOCK_LEN,
186210409Skib		    AES_BLOCK_LEN, ses->iv);
187210409Skib out1:
188210409Skib	if (allocated) {
189210409Skib		bzero(buf, enccrd->crd_len);
190210409Skib		free(buf, M_AESNI);
191210409Skib	}
192210409Skib out:
193210409Skib	return (error);
194210409Skib}
195