xref: /freebsd/sys/crypto/via/padlock_cipher.c (revision fdafd315)
15333bd47SPawel Jakub Dawidek /*-
25333bd47SPawel Jakub Dawidek  * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
35333bd47SPawel Jakub Dawidek  * Copyright (c) 2004 Mark R V Murray
45333bd47SPawel Jakub Dawidek  * All rights reserved.
55333bd47SPawel Jakub Dawidek  *
65333bd47SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
75333bd47SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
85333bd47SPawel Jakub Dawidek  * are met:
95333bd47SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
105333bd47SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
115333bd47SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
125333bd47SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
135333bd47SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
145333bd47SPawel Jakub Dawidek  *
155333bd47SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
165333bd47SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175333bd47SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185333bd47SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
195333bd47SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205333bd47SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215333bd47SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225333bd47SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235333bd47SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245333bd47SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255333bd47SPawel Jakub Dawidek  * SUCH DAMAGE.
265333bd47SPawel Jakub Dawidek  */
275333bd47SPawel Jakub Dawidek 
285333bd47SPawel Jakub Dawidek /*	$OpenBSD: via.c,v 1.3 2004/06/15 23:36:55 deraadt Exp $	*/
295333bd47SPawel Jakub Dawidek /*-
305333bd47SPawel Jakub Dawidek  * Copyright (c) 2003 Jason Wright
315333bd47SPawel Jakub Dawidek  * Copyright (c) 2003, 2004 Theo de Raadt
325333bd47SPawel Jakub Dawidek  * All rights reserved.
335333bd47SPawel Jakub Dawidek  *
345333bd47SPawel Jakub Dawidek  * Permission to use, copy, modify, and distribute this software for any
355333bd47SPawel Jakub Dawidek  * purpose with or without fee is hereby granted, provided that the above
365333bd47SPawel Jakub Dawidek  * copyright notice and this permission notice appear in all copies.
375333bd47SPawel Jakub Dawidek  *
385333bd47SPawel Jakub Dawidek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
395333bd47SPawel Jakub Dawidek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
405333bd47SPawel Jakub Dawidek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
415333bd47SPawel Jakub Dawidek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
425333bd47SPawel Jakub Dawidek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
435333bd47SPawel Jakub Dawidek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
445333bd47SPawel Jakub Dawidek  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
455333bd47SPawel Jakub Dawidek  */
465333bd47SPawel Jakub Dawidek 
475333bd47SPawel Jakub Dawidek #include <sys/param.h>
485333bd47SPawel Jakub Dawidek #include <sys/systm.h>
495333bd47SPawel Jakub Dawidek #include <sys/kernel.h>
505333bd47SPawel Jakub Dawidek #include <sys/module.h>
515333bd47SPawel Jakub Dawidek #include <sys/malloc.h>
525333bd47SPawel Jakub Dawidek #include <sys/libkern.h>
5304c49e68SKonstantin Belousov #include <sys/pcpu.h>
54b623eec5SPawel Jakub Dawidek #include <sys/uio.h>
553b0e353fSJohn Baldwin #include <machine/fpu.h>
565333bd47SPawel Jakub Dawidek 
575333bd47SPawel Jakub Dawidek #include <opencrypto/cryptodev.h>
585333bd47SPawel Jakub Dawidek #include <crypto/rijndael/rijndael.h>
595333bd47SPawel Jakub Dawidek 
605333bd47SPawel Jakub Dawidek #include <crypto/via/padlock.h>
615333bd47SPawel Jakub Dawidek 
625333bd47SPawel Jakub Dawidek #define	PADLOCK_ROUND_COUNT_AES128	10
635333bd47SPawel Jakub Dawidek #define	PADLOCK_ROUND_COUNT_AES192	12
645333bd47SPawel Jakub Dawidek #define	PADLOCK_ROUND_COUNT_AES256	14
655333bd47SPawel Jakub Dawidek 
665333bd47SPawel Jakub Dawidek #define	PADLOCK_ALGORITHM_TYPE_AES	0
675333bd47SPawel Jakub Dawidek 
685333bd47SPawel Jakub Dawidek #define	PADLOCK_KEY_GENERATION_HW	0
695333bd47SPawel Jakub Dawidek #define	PADLOCK_KEY_GENERATION_SW	1
705333bd47SPawel Jakub Dawidek 
715333bd47SPawel Jakub Dawidek #define	PADLOCK_DIRECTION_ENCRYPT	0
725333bd47SPawel Jakub Dawidek #define	PADLOCK_DIRECTION_DECRYPT	1
735333bd47SPawel Jakub Dawidek 
745333bd47SPawel Jakub Dawidek #define	PADLOCK_KEY_SIZE_128	0
755333bd47SPawel Jakub Dawidek #define	PADLOCK_KEY_SIZE_192	1
765333bd47SPawel Jakub Dawidek #define	PADLOCK_KEY_SIZE_256	2
775333bd47SPawel Jakub Dawidek 
785333bd47SPawel Jakub Dawidek MALLOC_DECLARE(M_PADLOCK);
795333bd47SPawel Jakub Dawidek 
805333bd47SPawel Jakub Dawidek static __inline void
padlock_cbc(void * in,void * out,size_t count,void * key,union padlock_cw * cw,void * iv)815333bd47SPawel Jakub Dawidek padlock_cbc(void *in, void *out, size_t count, void *key, union padlock_cw *cw,
825333bd47SPawel Jakub Dawidek     void *iv)
835333bd47SPawel Jakub Dawidek {
845333bd47SPawel Jakub Dawidek 	/* The .byte line is really VIA C3 "xcrypt-cbc" instruction */
855333bd47SPawel Jakub Dawidek 	__asm __volatile(
865333bd47SPawel Jakub Dawidek 		"pushf				\n\t"
875333bd47SPawel Jakub Dawidek 		"popf				\n\t"
8864e12b41SDimitry Andric 		"rep				\n\t"
895333bd47SPawel Jakub Dawidek 		".byte	0x0f, 0xa7, 0xd0"
905333bd47SPawel Jakub Dawidek 			: "+a" (iv), "+c" (count), "+D" (out), "+S" (in)
915333bd47SPawel Jakub Dawidek 			: "b" (key), "d" (cw)
925333bd47SPawel Jakub Dawidek 			: "cc", "memory"
935333bd47SPawel Jakub Dawidek 		);
945333bd47SPawel Jakub Dawidek }
955333bd47SPawel Jakub Dawidek 
965333bd47SPawel Jakub Dawidek static void
padlock_cipher_key_setup(struct padlock_session * ses,const void * key,int klen)97c0341432SJohn Baldwin padlock_cipher_key_setup(struct padlock_session *ses, const void *key, int klen)
985333bd47SPawel Jakub Dawidek {
995333bd47SPawel Jakub Dawidek 	union padlock_cw *cw;
1005333bd47SPawel Jakub Dawidek 	int i;
1015333bd47SPawel Jakub Dawidek 
1025333bd47SPawel Jakub Dawidek 	cw = &ses->ses_cw;
1035333bd47SPawel Jakub Dawidek 	if (cw->cw_key_generation == PADLOCK_KEY_GENERATION_SW) {
1045333bd47SPawel Jakub Dawidek 		/* Build expanded keys for both directions */
105c0341432SJohn Baldwin 		rijndaelKeySetupEnc(ses->ses_ekey, key, klen * 8);
106c0341432SJohn Baldwin 		rijndaelKeySetupDec(ses->ses_dkey, key, klen * 8);
1075333bd47SPawel Jakub Dawidek 		for (i = 0; i < 4 * (RIJNDAEL_MAXNR + 1); i++) {
1085333bd47SPawel Jakub Dawidek 			ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
1095333bd47SPawel Jakub Dawidek 			ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
1105333bd47SPawel Jakub Dawidek 		}
1115333bd47SPawel Jakub Dawidek 	} else {
1125333bd47SPawel Jakub Dawidek 		bcopy(key, ses->ses_ekey, klen);
1135333bd47SPawel Jakub Dawidek 		bcopy(key, ses->ses_dkey, klen);
1145333bd47SPawel Jakub Dawidek 	}
1155333bd47SPawel Jakub Dawidek }
1165333bd47SPawel Jakub Dawidek 
1175333bd47SPawel Jakub Dawidek int
padlock_cipher_setup(struct padlock_session * ses,const struct crypto_session_params * csp)118c0341432SJohn Baldwin padlock_cipher_setup(struct padlock_session *ses,
119c0341432SJohn Baldwin     const struct crypto_session_params *csp)
1205333bd47SPawel Jakub Dawidek {
1215333bd47SPawel Jakub Dawidek 	union padlock_cw *cw;
1225333bd47SPawel Jakub Dawidek 
123b4fef8d0SAlan Somers 	if (csp->csp_cipher_klen != 16 && csp->csp_cipher_klen != 24 &&
124c0341432SJohn Baldwin 	    csp->csp_cipher_klen != 32) {
1255333bd47SPawel Jakub Dawidek 		return (EINVAL);
1265333bd47SPawel Jakub Dawidek 	}
1275333bd47SPawel Jakub Dawidek 
1285333bd47SPawel Jakub Dawidek 	cw = &ses->ses_cw;
1295333bd47SPawel Jakub Dawidek 	bzero(cw, sizeof(*cw));
1305333bd47SPawel Jakub Dawidek 	cw->cw_algorithm_type = PADLOCK_ALGORITHM_TYPE_AES;
1315333bd47SPawel Jakub Dawidek 	cw->cw_key_generation = PADLOCK_KEY_GENERATION_SW;
1325333bd47SPawel Jakub Dawidek 	cw->cw_intermediate = 0;
133c0341432SJohn Baldwin 	switch (csp->csp_cipher_klen * 8) {
1345333bd47SPawel Jakub Dawidek 	case 128:
1355333bd47SPawel Jakub Dawidek 		cw->cw_round_count = PADLOCK_ROUND_COUNT_AES128;
1365333bd47SPawel Jakub Dawidek 		cw->cw_key_size = PADLOCK_KEY_SIZE_128;
1375333bd47SPawel Jakub Dawidek #ifdef HW_KEY_GENERATION
1385333bd47SPawel Jakub Dawidek 		/* This doesn't buy us much, that's why it is commented out. */
1395333bd47SPawel Jakub Dawidek 		cw->cw_key_generation = PADLOCK_KEY_GENERATION_HW;
1405333bd47SPawel Jakub Dawidek #endif
1415333bd47SPawel Jakub Dawidek 		break;
1425333bd47SPawel Jakub Dawidek 	case 192:
1435333bd47SPawel Jakub Dawidek 		cw->cw_round_count = PADLOCK_ROUND_COUNT_AES192;
1445333bd47SPawel Jakub Dawidek 		cw->cw_key_size = PADLOCK_KEY_SIZE_192;
1455333bd47SPawel Jakub Dawidek 		break;
1465333bd47SPawel Jakub Dawidek 	case 256:
1475333bd47SPawel Jakub Dawidek 		cw->cw_round_count = PADLOCK_ROUND_COUNT_AES256;
1485333bd47SPawel Jakub Dawidek 		cw->cw_key_size = PADLOCK_KEY_SIZE_256;
1495333bd47SPawel Jakub Dawidek 		break;
1505333bd47SPawel Jakub Dawidek 	}
151c0341432SJohn Baldwin 	if (csp->csp_cipher_key != NULL) {
152c0341432SJohn Baldwin 		padlock_cipher_key_setup(ses, csp->csp_cipher_key,
153c0341432SJohn Baldwin 		    csp->csp_cipher_klen);
1545333bd47SPawel Jakub Dawidek 	}
1555333bd47SPawel Jakub Dawidek 	return (0);
1565333bd47SPawel Jakub Dawidek }
1575333bd47SPawel Jakub Dawidek 
158b623eec5SPawel Jakub Dawidek /*
159b623eec5SPawel Jakub Dawidek  * Function checks if the given buffer is already 16 bytes aligned.
160b623eec5SPawel Jakub Dawidek  * If it is there is no need to allocate new buffer.
161b623eec5SPawel Jakub Dawidek  * If it isn't, new buffer is allocated.
162b623eec5SPawel Jakub Dawidek  */
163b623eec5SPawel Jakub Dawidek static u_char *
padlock_cipher_alloc(struct cryptop * crp,int * allocated)164c0341432SJohn Baldwin padlock_cipher_alloc(struct cryptop *crp, int *allocated)
165b623eec5SPawel Jakub Dawidek {
166b623eec5SPawel Jakub Dawidek 	u_char *addr;
167b623eec5SPawel Jakub Dawidek 
168f91ab858SJohn Baldwin 	addr = crypto_contiguous_subsegment(crp, crp->crp_payload_start,
169f91ab858SJohn Baldwin 	    crp->crp_payload_length);
170f91ab858SJohn Baldwin 	if (((uintptr_t)addr & 0xf) == 0) { /* 16 bytes aligned? */
171c0341432SJohn Baldwin 		*allocated = 0;
172c0341432SJohn Baldwin 		return (addr);
173c0341432SJohn Baldwin 	}
174c0341432SJohn Baldwin 
175b623eec5SPawel Jakub Dawidek 	*allocated = 1;
176c0341432SJohn Baldwin 	addr = malloc(crp->crp_payload_length + 16, M_PADLOCK, M_NOWAIT);
177b623eec5SPawel Jakub Dawidek 	return (addr);
178b623eec5SPawel Jakub Dawidek }
179b623eec5SPawel Jakub Dawidek 
1805333bd47SPawel Jakub Dawidek int
padlock_cipher_process(struct padlock_session * ses,struct cryptop * crp,const struct crypto_session_params * csp)181c0341432SJohn Baldwin padlock_cipher_process(struct padlock_session *ses, struct cryptop *crp,
182c0341432SJohn Baldwin     const struct crypto_session_params *csp)
1835333bd47SPawel Jakub Dawidek {
1845333bd47SPawel Jakub Dawidek 	union padlock_cw *cw;
18504c49e68SKonstantin Belousov 	struct thread *td;
1865333bd47SPawel Jakub Dawidek 	u_char *buf, *abuf;
1875333bd47SPawel Jakub Dawidek 	uint32_t *key;
188c0341432SJohn Baldwin 	uint8_t iv[AES_BLOCK_LEN] __aligned(16);
189849ce31aSConrad Meyer 	int allocated;
1905333bd47SPawel Jakub Dawidek 
191c0341432SJohn Baldwin 	buf = padlock_cipher_alloc(crp, &allocated);
1925333bd47SPawel Jakub Dawidek 	if (buf == NULL)
1935333bd47SPawel Jakub Dawidek 		return (ENOMEM);
1945333bd47SPawel Jakub Dawidek 	/* Buffer has to be 16 bytes aligned. */
1955333bd47SPawel Jakub Dawidek 	abuf = PADLOCK_ALIGN(buf);
1965333bd47SPawel Jakub Dawidek 
197c0341432SJohn Baldwin 	if (crp->crp_cipher_key != NULL) {
198c0341432SJohn Baldwin 		padlock_cipher_key_setup(ses, crp->crp_cipher_key,
199c0341432SJohn Baldwin 		    csp->csp_cipher_klen);
2005333bd47SPawel Jakub Dawidek 	}
2015333bd47SPawel Jakub Dawidek 
2025333bd47SPawel Jakub Dawidek 	cw = &ses->ses_cw;
2035333bd47SPawel Jakub Dawidek 	cw->cw_filler0 = 0;
2045333bd47SPawel Jakub Dawidek 	cw->cw_filler1 = 0;
2055333bd47SPawel Jakub Dawidek 	cw->cw_filler2 = 0;
2065333bd47SPawel Jakub Dawidek 	cw->cw_filler3 = 0;
207c0341432SJohn Baldwin 
20829fe41ddSJohn Baldwin 	crypto_read_iv(crp, iv);
209c0341432SJohn Baldwin 
210c0341432SJohn Baldwin 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
2115333bd47SPawel Jakub Dawidek 		cw->cw_direction = PADLOCK_DIRECTION_ENCRYPT;
2125333bd47SPawel Jakub Dawidek 		key = ses->ses_ekey;
2135333bd47SPawel Jakub Dawidek 	} else {
2145333bd47SPawel Jakub Dawidek 		cw->cw_direction = PADLOCK_DIRECTION_DECRYPT;
2155333bd47SPawel Jakub Dawidek 		key = ses->ses_dkey;
2165333bd47SPawel Jakub Dawidek 	}
2175333bd47SPawel Jakub Dawidek 
218b623eec5SPawel Jakub Dawidek 	if (allocated) {
219c0341432SJohn Baldwin 		crypto_copydata(crp, crp->crp_payload_start,
220c0341432SJohn Baldwin 		    crp->crp_payload_length, abuf);
221b623eec5SPawel Jakub Dawidek 	}
2225333bd47SPawel Jakub Dawidek 
22304c49e68SKonstantin Belousov 	td = curthread;
2243b0e353fSJohn Baldwin 	fpu_kern_enter(td, NULL, FPU_KERN_NORMAL | FPU_KERN_NOCTX);
225c0341432SJohn Baldwin 	padlock_cbc(abuf, abuf, crp->crp_payload_length / AES_BLOCK_LEN, key,
226c0341432SJohn Baldwin 	    cw, iv);
2273b0e353fSJohn Baldwin 	fpu_kern_leave(td, NULL);
22804c49e68SKonstantin Belousov 
229b623eec5SPawel Jakub Dawidek 	if (allocated) {
230c0341432SJohn Baldwin 		crypto_copyback(crp, crp->crp_payload_start,
231c0341432SJohn Baldwin 		    crp->crp_payload_length, abuf);
2325333bd47SPawel Jakub Dawidek 
2334a711b8dSJohn Baldwin 		zfree(buf, M_PADLOCK);
2345333bd47SPawel Jakub Dawidek 	}
235849ce31aSConrad Meyer 	return (0);
2365333bd47SPawel Jakub Dawidek }
237