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