g_eli_crypto.c revision 157900
1193323Sed/*-
2193323Sed * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3193323Sed * All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions
7193323Sed * are met:
8193323Sed * 1. Redistributions of source code must retain the above copyright
9193323Sed *    notice, this list of conditions and the following disclaimer.
10193323Sed * 2. Redistributions in binary form must reproduce the above copyright
11249423Sdim *    notice, this list of conditions and the following disclaimer in the
12193323Sed *    documentation and/or other materials provided with the distribution.
13193323Sed *
14193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15263508Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16202878Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18249423Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19198090Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20202878Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21202878Srdivacky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22206083Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23201360Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24198090Srdivacky * SUCH DAMAGE.
25198090Srdivacky */
26202878Srdivacky
27263508Sdim#include <sys/cdefs.h>
28193323Sed__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_crypto.c 157900 2006-04-20 06:33:46Z pjd $");
29193323Sed
30193323Sed#include <sys/param.h>
31193323Sed#ifdef _KERNEL
32193323Sed#include <sys/systm.h>
33193323Sed#include <sys/kernel.h>
34193323Sed#include <sys/malloc.h>
35193323Sed#include <sys/uio.h>
36193323Sed#else
37263508Sdim#include <stdint.h>
38263508Sdim#include <string.h>
39263508Sdim#include <strings.h>
40263508Sdim#include <errno.h>
41193323Sed#include <assert.h>
42193323Sed#include <openssl/evp.h>
43193323Sed#define	_OpenSSL_
44193323Sed#endif
45193323Sed#include <geom/eli/g_eli.h>
46193323Sed
47193323Sed#ifdef _KERNEL
48193323SedMALLOC_DECLARE(M_ELI);
49193323Sed
50263508Sdimstatic int
51193323Sedg_eli_crypto_done(struct cryptop *crp)
52193323Sed{
53193323Sed
54193323Sed	crp->crp_opaque = (void *)crp;
55193323Sed	wakeup(crp);
56193323Sed	return (0);
57193323Sed}
58193323Sed
59193323Sedstatic int
60206274Srdivackyg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
61193323Sed    const u_char *key, size_t keysize)
62206274Srdivacky{
63193323Sed	struct cryptoini cri;
64193323Sed	struct cryptop *crp;
65206274Srdivacky	struct cryptodesc *crd;
66193323Sed	struct uio *uio;
67193323Sed	struct iovec *iov;
68193323Sed	uint64_t sid;
69193323Sed	u_char *p;
70193323Sed	int error;
71193323Sed
72206274Srdivacky	bzero(&cri, sizeof(cri));
73226633Sdim	cri.cri_alg = algo;
74193323Sed	cri.cri_key = __DECONST(void *, key);
75193323Sed	cri.cri_klen = keysize;
76206274Srdivacky	error = crypto_newsession(&sid, &cri, 0);
77202878Srdivacky	if (error != 0)
78193323Sed		return (error);
79193323Sed	p = malloc(sizeof(*crp) + sizeof(*crd) + sizeof(*uio) + sizeof(*iov),
80193323Sed	    M_ELI, M_NOWAIT | M_ZERO);
81206274Srdivacky	if (p == NULL) {
82206274Srdivacky		crypto_freesession(sid);
83193323Sed		return (ENOMEM);
84193323Sed	}
85193323Sed	crp = (struct cryptop *)p;	p += sizeof(*crp);
86198090Srdivacky	crd = (struct cryptodesc *)p;	p += sizeof(*crd);
87193323Sed	uio = (struct uio *)p;		p += sizeof(*uio);
88198090Srdivacky	iov = (struct iovec *)p;	p += sizeof(*iov);
89193323Sed
90193323Sed	iov->iov_len = datasize;
91193323Sed	iov->iov_base = data;
92193323Sed
93198090Srdivacky	uio->uio_iov = iov;
94193323Sed	uio->uio_iovcnt = 1;
95193323Sed	uio->uio_segflg = UIO_SYSSPACE;
96193323Sed	uio->uio_resid = datasize;
97193323Sed
98193323Sed	crd->crd_skip = 0;
99193323Sed	crd->crd_len = datasize;
100198090Srdivacky	crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
101193323Sed	if (enc)
102193323Sed		crd->crd_flags |= CRD_F_ENCRYPT;
103201360Srdivacky	crd->crd_alg = algo;
104193323Sed	crd->crd_key = __DECONST(void *, key);
105193323Sed	crd->crd_klen = keysize;
106193323Sed	bzero(crd->crd_iv, sizeof(crd->crd_iv));
107193323Sed	crd->crd_next = NULL;
108193323Sed
109193323Sed	crp->crp_sid = sid;
110193323Sed	crp->crp_ilen = datasize;
111193323Sed	crp->crp_olen = datasize;
112193323Sed	crp->crp_opaque = NULL;
113193323Sed	crp->crp_callback = g_eli_crypto_done;
114193323Sed	crp->crp_buf = (void *)uio;
115251662Sdim	crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIFSYNC | CRYPTO_F_REL;
116251662Sdim	crp->crp_desc = crd;
117263508Sdim
118263508Sdim	error = crypto_dispatch(crp);
119263508Sdim	if (error == 0) {
120263508Sdim		while (crp->crp_opaque == NULL)
121263508Sdim			tsleep(crp, PRIBIO, "geli", hz / 5);
122263508Sdim		error = crp->crp_etype;
123263508Sdim	}
124263508Sdim
125263508Sdim	free(crp, M_ELI);
126263508Sdim	crypto_freesession(sid);
127249423Sdim	return (error);
128249423Sdim}
129249423Sdim#else	/* !_KERNEL */
130249423Sdimstatic int
131249423Sdimg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
132263508Sdim    const u_char *key, size_t keysize)
133249423Sdim{
134249423Sdim	EVP_CIPHER_CTX ctx;
135263508Sdim	const EVP_CIPHER *type;
136263508Sdim	u_char iv[keysize];
137263508Sdim	int outsize;
138263508Sdim
139263508Sdim	switch (algo) {
140263508Sdim	case CRYPTO_NULL_CBC:
141263508Sdim		type = EVP_enc_null();
142263508Sdim		break;
143263508Sdim	case CRYPTO_AES_CBC:
144263508Sdim		switch (keysize) {
145263508Sdim		case 128:
146263508Sdim			type = EVP_aes_128_cbc();
147193323Sed			break;
148251662Sdim		case 192:
149193323Sed			type = EVP_aes_192_cbc();
150193323Sed			break;
151193323Sed		case 256:
152193323Sed			type = EVP_aes_256_cbc();
153193323Sed			break;
154193323Sed		default:
155198090Srdivacky			return (EINVAL);
156193323Sed		}
157204961Srdivacky		break;
158193323Sed	case CRYPTO_BLF_CBC:
159193323Sed		type = EVP_bf_cbc();
160193323Sed		break;
161193323Sed	case CRYPTO_3DES_CBC:
162204961Srdivacky		type = EVP_des_ede3_cbc();
163193323Sed		break;
164204961Srdivacky	default:
165193323Sed		return (EINVAL);
166193323Sed	}
167249423Sdim
168193323Sed	EVP_CIPHER_CTX_init(&ctx);
169193323Sed
170193323Sed	EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc);
171193323Sed	EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8);
172193323Sed	EVP_CIPHER_CTX_set_padding(&ctx, 0);
173193323Sed	bzero(iv, sizeof(iv));
174193323Sed	EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc);
175193323Sed
176193323Sed	if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) {
177193323Sed		EVP_CIPHER_CTX_cleanup(&ctx);
178193323Sed		return (EINVAL);
179193323Sed	}
180193323Sed	assert(outsize == (int)datasize);
181193323Sed
182193323Sed	if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) {
183193323Sed		EVP_CIPHER_CTX_cleanup(&ctx);
184193323Sed		return (EINVAL);
185193323Sed	}
186193323Sed	assert(outsize == 0);
187251662Sdim
188193323Sed	EVP_CIPHER_CTX_cleanup(&ctx);
189193323Sed	return (0);
190193323Sed}
191193323Sed#endif	/* !_KERNEL */
192193323Sed
193193323Sedint
194201360Srdivackyg_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
195193323Sed    const u_char *key, size_t keysize)
196193323Sed{
197193323Sed
198234353Sdim	return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
199193323Sed}
200193323Sed
201263508Sdimint
202201360Srdivackyg_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
203193323Sed    const u_char *key, size_t keysize)
204193323Sed{
205193323Sed
206193323Sed	return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
207193323Sed}
208193323Sed
209193323Sedvoid
210193323Sedg_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey,
211193323Sed    size_t hkeylen)
212263508Sdim{
213202878Srdivacky	u_char k_ipad[128], key[128];
214193323Sed	SHA512_CTX lctx;
215243830Sdim	u_int i;
216243830Sdim
217243830Sdim	bzero(key, sizeof(key));
218243830Sdim	if (hkeylen == 0)
219263508Sdim		; /* do nothing */
220243830Sdim	else if (hkeylen <= 128)
221193323Sed		bcopy(hkey, key, hkeylen);
222193323Sed	else {
223202878Srdivacky		/* If key is longer than 128 bytes reset it to key = SHA512(key). */
224193323Sed		SHA512_Init(&lctx);
225202878Srdivacky		SHA512_Update(&lctx, hkey, hkeylen);
226249423Sdim		SHA512_Final(key, &lctx);
227193323Sed	}
228202878Srdivacky
229193323Sed	/* XOR key with ipad and opad values. */
230202878Srdivacky	for (i = 0; i < sizeof(key); i++) {
231249423Sdim		k_ipad[i] = key[i] ^ 0x36;
232249423Sdim		ctx->k_opad[i] = key[i] ^ 0x5c;
233206274Srdivacky	}
234206274Srdivacky	bzero(key, sizeof(key));
235243830Sdim	/* Perform inner SHA512. */
236243830Sdim	SHA512_Init(&ctx->shactx);
237198090Srdivacky	SHA512_Update(&ctx->shactx, k_ipad, sizeof(k_ipad));
238193323Sed}
239249423Sdim
240193323Sedvoid
241193323Sedg_eli_crypto_hmac_update(struct hmac_ctx *ctx, const uint8_t *data,
242193323Sed    size_t datasize)
243193323Sed{
244263508Sdim
245193323Sed	SHA512_Update(&ctx->shactx, data, datasize);
246243830Sdim}
247193323Sed
248193323Sedvoid
249193323Sedg_eli_crypto_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize)
250193323Sed{
251193323Sed	u_char digest[SHA512_MDLEN];
252249423Sdim	SHA512_CTX lctx;
253193323Sed
254193323Sed	SHA512_Final(digest, &ctx->shactx);
255193323Sed	/* Perform outer SHA512. */
256193323Sed	SHA512_Init(&lctx);
257249423Sdim	SHA512_Update(&lctx, ctx->k_opad, sizeof(ctx->k_opad));
258249423Sdim	bzero(ctx, sizeof(*ctx));
259198090Srdivacky	SHA512_Update(&lctx, digest, sizeof(digest));
260198090Srdivacky	SHA512_Final(digest, &lctx);
261243830Sdim	/* mdsize == 0 means "Give me the whole hash!" */
262234353Sdim	if (mdsize == 0)
263193323Sed		mdsize = SHA512_MDLEN;
264193323Sed	bcopy(digest, md, mdsize);
265193323Sed}
266193323Sed
267263508Sdimvoid
268234353Sdimg_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data,
269234353Sdim    size_t datasize, uint8_t *md, size_t mdsize)
270193323Sed{
271193323Sed	struct hmac_ctx ctx;
272193323Sed
273193323Sed	g_eli_crypto_hmac_init(&ctx, hkey, hkeysize);
274263508Sdim	g_eli_crypto_hmac_update(&ctx, data, datasize);
275263508Sdim	g_eli_crypto_hmac_final(&ctx, md, mdsize);
276263508Sdim}
277263508Sdim