g_eli_crypto.c revision 271148
169450Smsmith/*-
269450Smsmith * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3167802Sjkim * All rights reserved.
4167802Sjkim *
569450Smsmith * Redistribution and use in source and binary forms, with or without
669450Smsmith * modification, are permitted provided that the following conditions
769450Smsmith * are met:
869450Smsmith * 1. Redistributions of source code must retain the above copyright
969450Smsmith *    notice, this list of conditions and the following disclaimer.
1069450Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1169450Smsmith *    notice, this list of conditions and the following disclaimer in the
12167802Sjkim *    documentation and/or other materials provided with the distribution.
1370243Smsmith *
1469450Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1569450Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1669450Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1769450Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1869450Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1969450Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2069450Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2169450Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2269450Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2369450Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2469450Smsmith * SUCH DAMAGE.
2569450Smsmith */
2669450Smsmith
2769450Smsmith#include <sys/cdefs.h>
2869450Smsmith__FBSDID("$FreeBSD: head/sys/geom/eli/g_eli_crypto.c 271148 2014-09-04 23:53:51Z jmg $");
2969450Smsmith
3069450Smsmith#include <sys/param.h>
3169450Smsmith#ifdef _KERNEL
3269450Smsmith#include <sys/systm.h>
3369450Smsmith#include <sys/kernel.h>
3469450Smsmith#include <sys/malloc.h>
3569450Smsmith#else
3669450Smsmith#include <stdint.h>
3769450Smsmith#include <string.h>
3869450Smsmith#include <strings.h>
3969450Smsmith#include <errno.h>
4069450Smsmith#include <assert.h>
4169450Smsmith#include <openssl/evp.h>
4269450Smsmith#define	_OpenSSL_
4369450Smsmith#endif
4469450Smsmith#include <geom/eli/g_eli.h>
4569450Smsmith
4669450Smsmith#ifdef _KERNEL
4769450SmsmithMALLOC_DECLARE(M_ELI);
4869450Smsmith
4969450Smsmithstatic int
5069450Smsmithg_eli_crypto_done(struct cryptop *crp)
5169450Smsmith{
5269450Smsmith
5369450Smsmith	crp->crp_opaque = (void *)crp;
5469450Smsmith	wakeup(crp);
5569450Smsmith	return (0);
5669450Smsmith}
5769450Smsmith
5869450Smsmithstatic int
5969450Smsmithg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
6069450Smsmith    const u_char *key, size_t keysize)
6169450Smsmith{
6269450Smsmith	struct cryptoini cri;
6369450Smsmith	struct cryptop *crp;
6469450Smsmith	struct cryptodesc *crd;
6569450Smsmith	uint64_t sid;
6669450Smsmith	u_char *p;
6769450Smsmith	int error;
6869450Smsmith
6969450Smsmith	KASSERT(algo != CRYPTO_AES_XTS,
7069450Smsmith	    ("%s: CRYPTO_AES_XTS unexpected here", __func__));
7169450Smsmith
7269450Smsmith	bzero(&cri, sizeof(cri));
7369450Smsmith	cri.cri_alg = algo;
7469450Smsmith	cri.cri_key = __DECONST(void *, key);
7569450Smsmith	cri.cri_klen = keysize;
7669450Smsmith	error = crypto_newsession(&sid, &cri, CRYPTOCAP_F_SOFTWARE);
7769450Smsmith	if (error != 0)
7869450Smsmith		return (error);
7969450Smsmith	p = malloc(sizeof(*crp) + sizeof(*crd), M_ELI, M_NOWAIT | M_ZERO);
8069450Smsmith	if (p == NULL) {
8169450Smsmith		crypto_freesession(sid);
8269450Smsmith		return (ENOMEM);
8369450Smsmith	}
8469450Smsmith	crp = (struct cryptop *)p;	p += sizeof(*crp);
8569450Smsmith	crd = (struct cryptodesc *)p;	p += sizeof(*crd);
8669450Smsmith
8769450Smsmith	crd->crd_skip = 0;
8869450Smsmith	crd->crd_len = datasize;
8969450Smsmith	crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
9069450Smsmith	if (enc)
9169450Smsmith		crd->crd_flags |= CRD_F_ENCRYPT;
9269450Smsmith	crd->crd_alg = algo;
9369450Smsmith	crd->crd_key = __DECONST(void *, key);
9469450Smsmith	crd->crd_klen = keysize;
9569450Smsmith	bzero(crd->crd_iv, sizeof(crd->crd_iv));
9669450Smsmith	crd->crd_next = NULL;
9769450Smsmith
9869450Smsmith	crp->crp_sid = sid;
9969450Smsmith	crp->crp_ilen = datasize;
10069450Smsmith	crp->crp_olen = datasize;
10169450Smsmith	crp->crp_opaque = NULL;
10269450Smsmith	crp->crp_callback = g_eli_crypto_done;
10369450Smsmith	crp->crp_buf = (void *)data;
10469450Smsmith	crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_REL;
10569450Smsmith	crp->crp_desc = crd;
10669450Smsmith
10769450Smsmith	error = crypto_dispatch(crp);
10869450Smsmith	if (error == 0) {
10969450Smsmith		while (crp->crp_opaque == NULL)
11069450Smsmith			tsleep(crp, PRIBIO, "geli", hz / 5);
11169450Smsmith		error = crp->crp_etype;
11269450Smsmith	}
11369450Smsmith
11469450Smsmith	free(crp, M_ELI);
11569450Smsmith	crypto_freesession(sid);
11669450Smsmith	return (error);
11769450Smsmith}
11869450Smsmith#else	/* !_KERNEL */
11969450Smsmithstatic int
120167802Sjkimg_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize,
121167802Sjkim    const u_char *key, size_t keysize)
122167802Sjkim{
123167802Sjkim	EVP_CIPHER_CTX ctx;
124167802Sjkim	const EVP_CIPHER *type;
125167802Sjkim	u_char iv[keysize];
126167802Sjkim	int outsize;
127167802Sjkim
128167802Sjkim	assert(algo != CRYPTO_AES_XTS);
129167802Sjkim
130167802Sjkim	switch (algo) {
131167802Sjkim	case CRYPTO_NULL_CBC:
132167802Sjkim		type = EVP_enc_null();
133167802Sjkim		break;
134167802Sjkim	case CRYPTO_AES_CBC:
135167802Sjkim		switch (keysize) {
136167802Sjkim		case 128:
137167802Sjkim			type = EVP_aes_128_cbc();
138167802Sjkim			break;
139167802Sjkim		case 192:
140167802Sjkim			type = EVP_aes_192_cbc();
141167802Sjkim			break;
142167802Sjkim		case 256:
143167802Sjkim			type = EVP_aes_256_cbc();
144167802Sjkim			break;
145167802Sjkim		default:
146167802Sjkim			return (EINVAL);
147167802Sjkim		}
148167802Sjkim		break;
149167802Sjkim	case CRYPTO_BLF_CBC:
150167802Sjkim		type = EVP_bf_cbc();
151167802Sjkim		break;
152167802Sjkim#ifndef OPENSSL_NO_CAMELLIA
153167802Sjkim	case CRYPTO_CAMELLIA_CBC:
154167802Sjkim		switch (keysize) {
155167802Sjkim		case 128:
156167802Sjkim			type = EVP_camellia_128_cbc();
15769450Smsmith			break;
15869450Smsmith		case 192:
15991116Smsmith			type = EVP_camellia_192_cbc();
160167802Sjkim			break;
161167802Sjkim		case 256:
162167802Sjkim			type = EVP_camellia_256_cbc();
16391116Smsmith			break;
164167802Sjkim		default:
165167802Sjkim			return (EINVAL);
166167802Sjkim		}
167167802Sjkim		break;
168167802Sjkim#endif
16969450Smsmith	case CRYPTO_3DES_CBC:
170167802Sjkim		type = EVP_des_ede3_cbc();
171167802Sjkim		break;
172151937Sjkim	default:
173167802Sjkim		return (EINVAL);
17469450Smsmith	}
17569450Smsmith
176167802Sjkim	EVP_CIPHER_CTX_init(&ctx);
177167802Sjkim
178167802Sjkim	EVP_CipherInit_ex(&ctx, type, NULL, NULL, NULL, enc);
179167802Sjkim	EVP_CIPHER_CTX_set_key_length(&ctx, keysize / 8);
180167802Sjkim	EVP_CIPHER_CTX_set_padding(&ctx, 0);
181167802Sjkim	bzero(iv, sizeof(iv));
182167802Sjkim	EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, enc);
183167802Sjkim
184167802Sjkim	if (EVP_CipherUpdate(&ctx, data, &outsize, data, datasize) == 0) {
185167802Sjkim		EVP_CIPHER_CTX_cleanup(&ctx);
186167802Sjkim		return (EINVAL);
187167802Sjkim	}
188167802Sjkim	assert(outsize == (int)datasize);
189167802Sjkim
190167802Sjkim	if (EVP_CipherFinal_ex(&ctx, data + outsize, &outsize) == 0) {
191167802Sjkim		EVP_CIPHER_CTX_cleanup(&ctx);
192167802Sjkim		return (EINVAL);
193167802Sjkim	}
194167802Sjkim	assert(outsize == 0);
195167802Sjkim
196167802Sjkim	EVP_CIPHER_CTX_cleanup(&ctx);
197167802Sjkim	return (0);
198167802Sjkim}
199167802Sjkim#endif	/* !_KERNEL */
200167802Sjkim
201167802Sjkimint
202167802Sjkimg_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize,
203167802Sjkim    const u_char *key, size_t keysize)
204167802Sjkim{
205167802Sjkim
206167802Sjkim	/* We prefer AES-CBC for metadata protection. */
207167802Sjkim	if (algo == CRYPTO_AES_XTS)
208167802Sjkim		algo = CRYPTO_AES_CBC;
209167802Sjkim
210167802Sjkim	return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize));
211167802Sjkim}
212167802Sjkim
213167802Sjkimint
21491116Smsmithg_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize,
215167802Sjkim    const u_char *key, size_t keysize)
21691116Smsmith{
217167802Sjkim
218167802Sjkim	/* We prefer AES-CBC for metadata protection. */
219167802Sjkim	if (algo == CRYPTO_AES_XTS)
220167802Sjkim		algo = CRYPTO_AES_CBC;
22169450Smsmith
222167802Sjkim	return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize));
223167802Sjkim}
224167802Sjkim
225167802Sjkimvoid
226167802Sjkimg_eli_crypto_hmac_init(struct hmac_ctx *ctx, const uint8_t *hkey,
227167802Sjkim    size_t hkeylen)
228167802Sjkim{
22969450Smsmith	u_char k_ipad[128], key[128];
230167802Sjkim	SHA512_CTX lctx;
231151937Sjkim	u_int i;
232167802Sjkim
233151937Sjkim	bzero(key, sizeof(key));
234167802Sjkim	if (hkeylen == 0)
235167802Sjkim		; /* do nothing */
236167802Sjkim	else if (hkeylen <= 128)
237167802Sjkim		bcopy(hkey, key, hkeylen);
238167802Sjkim	else {
239167802Sjkim		/* If key is longer than 128 bytes reset it to key = SHA512(key). */
240167802Sjkim		SHA512_Init(&lctx);
241151937Sjkim		SHA512_Update(&lctx, hkey, hkeylen);
242167802Sjkim		SHA512_Final(key, &lctx);
24369450Smsmith	}
244167802Sjkim
245167802Sjkim	/* XOR key with ipad and opad values. */
246167802Sjkim	for (i = 0; i < sizeof(key); i++) {
247167802Sjkim		k_ipad[i] = key[i] ^ 0x36;
248167802Sjkim		ctx->k_opad[i] = key[i] ^ 0x5c;
249167802Sjkim	}
250167802Sjkim	bzero(key, sizeof(key));
251167802Sjkim	/* Perform inner SHA512. */
252167802Sjkim	SHA512_Init(&ctx->shactx);
253167802Sjkim	SHA512_Update(&ctx->shactx, k_ipad, sizeof(k_ipad));
254167802Sjkim	bzero(k_ipad, sizeof(k_ipad));
255167802Sjkim}
256167802Sjkim
257167802Sjkimvoid
25869450Smsmithg_eli_crypto_hmac_update(struct hmac_ctx *ctx, const uint8_t *data,
259167802Sjkim    size_t datasize)
260167802Sjkim{
261167802Sjkim
262167802Sjkim	SHA512_Update(&ctx->shactx, data, datasize);
263167802Sjkim}
264167802Sjkim
265167802Sjkimvoid
266167802Sjkimg_eli_crypto_hmac_final(struct hmac_ctx *ctx, uint8_t *md, size_t mdsize)
267167802Sjkim{
268167802Sjkim	u_char digest[SHA512_MDLEN];
269167802Sjkim	SHA512_CTX lctx;
270167802Sjkim
271167802Sjkim	SHA512_Final(digest, &ctx->shactx);
272167802Sjkim	/* Perform outer SHA512. */
273167802Sjkim	SHA512_Init(&lctx);
274167802Sjkim	SHA512_Update(&lctx, ctx->k_opad, sizeof(ctx->k_opad));
275167802Sjkim	bzero(ctx, sizeof(*ctx));
276167802Sjkim	SHA512_Update(&lctx, digest, sizeof(digest));
277167802Sjkim	SHA512_Final(digest, &lctx);
278167802Sjkim	bzero(&lctx, sizeof(lctx));
279167802Sjkim	/* mdsize == 0 means "Give me the whole hash!" */
280167802Sjkim	if (mdsize == 0)
281167802Sjkim		mdsize = SHA512_MDLEN;
282167802Sjkim	bcopy(digest, md, mdsize);
283167802Sjkim	bzero(digest, sizeof(digest));
284167802Sjkim}
285167802Sjkim
286167802Sjkimvoid
287167802Sjkimg_eli_crypto_hmac(const uint8_t *hkey, size_t hkeysize, const uint8_t *data,
288167802Sjkim    size_t datasize, uint8_t *md, size_t mdsize)
289167802Sjkim{
290167802Sjkim	struct hmac_ctx ctx;
291167802Sjkim
292167802Sjkim	g_eli_crypto_hmac_init(&ctx, hkey, hkeysize);
293167802Sjkim	g_eli_crypto_hmac_update(&ctx, data, datasize);
294167802Sjkim	g_eli_crypto_hmac_final(&ctx, md, mdsize);
295167802Sjkim}
296167802Sjkim