1181467Sphilip/*-
2181467Sphilip * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3181467Sphilip * All rights reserved.
4181467Sphilip *
5181467Sphilip * Redistribution and use in source and binary forms, with or without
6181467Sphilip * modification, are permitted provided that the following conditions
7181467Sphilip * are met:
8181467Sphilip * 1. Redistributions of source code must retain the above copyright
9181467Sphilip *    notice, this list of conditions and the following disclaimer.
10181467Sphilip * 2. Redistributions in binary form must reproduce the above copyright
11181467Sphilip *    notice, this list of conditions and the following disclaimer in the
12181467Sphilip *    documentation and/or other materials provided with the distribution.
13181467Sphilip *
14181467Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15181467Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16181467Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17181467Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18181467Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19181467Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20181467Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21181467Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22181467Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23181467Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24181467Sphilip * SUCH DAMAGE.
25181467Sphilip */
26181467Sphilip
27181467Sphilip#include <sys/cdefs.h>
28181467Sphilip__FBSDID("$FreeBSD: releng/10.2/sys/dev/glxsb/glxsb_hash.c 181593 2008-08-11 08:41:08Z pjd $");
29181467Sphilip
30181467Sphilip#include <sys/param.h>
31181467Sphilip#include <sys/systm.h>
32181467Sphilip#include <sys/malloc.h>
33181467Sphilip
34181467Sphilip#include <opencrypto/cryptosoft.h> /* for hmac_ipad_buffer and hmac_opad_buffer */
35181467Sphilip#include <opencrypto/xform.h>
36181467Sphilip
37181467Sphilip#include "glxsb.h"
38181467Sphilip
39181467Sphilip/*
40181467Sphilip * Implementation notes.
41181467Sphilip *
42181467Sphilip * The Geode LX Security Block provides AES-128-CBC acceleration.
43181467Sphilip * We implement all HMAC algorithms provided by crypto(9) framework so glxsb can work
44181467Sphilip * with ipsec(4)
45181467Sphilip *
46181467Sphilip * This code was stolen from crypto/via/padlock_hash.c
47181467Sphilip */
48181467Sphilip
49181467SphilipMALLOC_DECLARE(M_GLXSB);
50181467Sphilip
51181467Sphilipstatic void
52181467Sphilipglxsb_hash_key_setup(struct glxsb_session *ses, caddr_t key, int klen)
53181467Sphilip{
54181467Sphilip	struct auth_hash *axf;
55181467Sphilip	int i;
56181467Sphilip
57181467Sphilip	klen /= 8;
58181467Sphilip	axf = ses->ses_axf;
59181467Sphilip
60181467Sphilip	for (i = 0; i < klen; i++)
61181467Sphilip		key[i] ^= HMAC_IPAD_VAL;
62181467Sphilip
63181467Sphilip	axf->Init(ses->ses_ictx);
64181467Sphilip	axf->Update(ses->ses_ictx, key, klen);
65181467Sphilip	axf->Update(ses->ses_ictx, hmac_ipad_buffer, axf->blocksize - klen);
66181467Sphilip
67181467Sphilip	for (i = 0; i < klen; i++)
68181467Sphilip		key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
69181467Sphilip
70181467Sphilip	axf->Init(ses->ses_octx);
71181467Sphilip	axf->Update(ses->ses_octx, key, klen);
72181467Sphilip	axf->Update(ses->ses_octx, hmac_opad_buffer, axf->blocksize - klen);
73181467Sphilip
74181467Sphilip	for (i = 0; i < klen; i++)
75181467Sphilip		key[i] ^= HMAC_OPAD_VAL;
76181467Sphilip}
77181467Sphilip
78181467Sphilip/*
79181467Sphilip * Compute keyed-hash authenticator.
80181467Sphilip */
81181467Sphilipstatic int
82181467Sphilipglxsb_authcompute(struct glxsb_session *ses, struct cryptodesc *crd,
83181467Sphilip    caddr_t buf, int flags)
84181467Sphilip{
85181467Sphilip	u_char hash[HASH_MAX_LEN];
86181467Sphilip	struct auth_hash *axf;
87181467Sphilip	union authctx ctx;
88181467Sphilip	int error;
89181467Sphilip
90181467Sphilip	axf = ses->ses_axf;
91181467Sphilip	bcopy(ses->ses_ictx, &ctx, axf->ctxsize);
92181467Sphilip	error = crypto_apply(flags, buf, crd->crd_skip, crd->crd_len,
93181467Sphilip	    (int (*)(void *, void *, unsigned int))axf->Update, (caddr_t)&ctx);
94181593Spjd	if (error != 0)
95181467Sphilip		return (error);
96181467Sphilip	axf->Final(hash, &ctx);
97181467Sphilip
98181467Sphilip	bcopy(ses->ses_octx, &ctx, axf->ctxsize);
99181467Sphilip	axf->Update(&ctx, hash, axf->hashsize);
100181467Sphilip	axf->Final(hash, &ctx);
101181467Sphilip
102181467Sphilip	/* Inject the authentication data */
103181467Sphilip	crypto_copyback(flags, buf, crd->crd_inject,
104181467Sphilip	ses->ses_mlen == 0 ? axf->hashsize : ses->ses_mlen, hash);
105181467Sphilip	return (0);
106181467Sphilip}
107181467Sphilip
108181467Sphilipint
109181467Sphilipglxsb_hash_setup(struct glxsb_session *ses, struct cryptoini *macini)
110181467Sphilip{
111181467Sphilip
112181467Sphilip	ses->ses_mlen = macini->cri_mlen;
113181467Sphilip
114181467Sphilip	/* Find software structure which describes HMAC algorithm. */
115181467Sphilip	switch (macini->cri_alg) {
116181467Sphilip	case CRYPTO_NULL_HMAC:
117181467Sphilip		ses->ses_axf = &auth_hash_null;
118181467Sphilip		break;
119181467Sphilip	case CRYPTO_MD5_HMAC:
120181467Sphilip		ses->ses_axf = &auth_hash_hmac_md5;
121181467Sphilip		break;
122181467Sphilip	case CRYPTO_SHA1_HMAC:
123181467Sphilip		ses->ses_axf = &auth_hash_hmac_sha1;
124181467Sphilip		break;
125181467Sphilip	case CRYPTO_RIPEMD160_HMAC:
126181467Sphilip		ses->ses_axf = &auth_hash_hmac_ripemd_160;
127181467Sphilip		break;
128181467Sphilip	case CRYPTO_SHA2_256_HMAC:
129181467Sphilip		ses->ses_axf = &auth_hash_hmac_sha2_256;
130181467Sphilip		break;
131181467Sphilip	case CRYPTO_SHA2_384_HMAC:
132181467Sphilip		ses->ses_axf = &auth_hash_hmac_sha2_384;
133181467Sphilip		break;
134181467Sphilip	case CRYPTO_SHA2_512_HMAC:
135181467Sphilip		ses->ses_axf = &auth_hash_hmac_sha2_512;
136181467Sphilip		break;
137181467Sphilip	}
138181467Sphilip
139181467Sphilip	/* Allocate memory for HMAC inner and outer contexts. */
140181467Sphilip	ses->ses_ictx = malloc(ses->ses_axf->ctxsize, M_GLXSB,
141181467Sphilip	    M_ZERO | M_NOWAIT);
142181467Sphilip	ses->ses_octx = malloc(ses->ses_axf->ctxsize, M_GLXSB,
143181467Sphilip	    M_ZERO | M_NOWAIT);
144181467Sphilip	if (ses->ses_ictx == NULL || ses->ses_octx == NULL)
145181467Sphilip		return (ENOMEM);
146181467Sphilip
147181467Sphilip	/* Setup key if given. */
148181467Sphilip	if (macini->cri_key != NULL) {
149181467Sphilip		glxsb_hash_key_setup(ses, macini->cri_key,
150181467Sphilip		    macini->cri_klen);
151181467Sphilip	}
152181467Sphilip	return (0);
153181467Sphilip}
154181467Sphilip
155181467Sphilipint
156181467Sphilipglxsb_hash_process(struct glxsb_session *ses, struct cryptodesc *maccrd,
157181467Sphilip    struct cryptop *crp)
158181467Sphilip{
159181467Sphilip	int error;
160181467Sphilip
161181467Sphilip	if ((maccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0)
162181467Sphilip		glxsb_hash_key_setup(ses, maccrd->crd_key, maccrd->crd_klen);
163181467Sphilip
164181467Sphilip	error = glxsb_authcompute(ses, maccrd, crp->crp_buf, crp->crp_flags);
165181467Sphilip	return (error);
166181467Sphilip}
167181467Sphilip
168181467Sphilipvoid
169181467Sphilipglxsb_hash_free(struct glxsb_session *ses)
170181467Sphilip{
171181467Sphilip
172181467Sphilip	if (ses->ses_ictx != NULL) {
173181467Sphilip		bzero(ses->ses_ictx, ses->ses_axf->ctxsize);
174181467Sphilip		free(ses->ses_ictx, M_GLXSB);
175181467Sphilip		ses->ses_ictx = NULL;
176181467Sphilip	}
177181467Sphilip	if (ses->ses_octx != NULL) {
178181467Sphilip		bzero(ses->ses_octx, ses->ses_axf->ctxsize);
179181467Sphilip		free(ses->ses_octx, M_GLXSB);
180181467Sphilip		ses->ses_octx = NULL;
181181467Sphilip	}
182181467Sphilip}
183