1184588Sdfr/*-
2184588Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3184588Sdfr * Authors: Doug Rabson <dfr@rabson.org>
4184588Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5184588Sdfr *
6184588Sdfr * Redistribution and use in source and binary forms, with or without
7184588Sdfr * modification, are permitted provided that the following conditions
8184588Sdfr * are met:
9184588Sdfr * 1. Redistributions of source code must retain the above copyright
10184588Sdfr *    notice, this list of conditions and the following disclaimer.
11184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright
12184588Sdfr *    notice, this list of conditions and the following disclaimer in the
13184588Sdfr *    documentation and/or other materials provided with the distribution.
14184588Sdfr *
15184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18184588Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25184588Sdfr * SUCH DAMAGE.
26184588Sdfr */
27184588Sdfr
28184588Sdfr#include <sys/cdefs.h>
29184588Sdfr__FBSDID("$FreeBSD: stable/11/sys/kgssapi/krb5/kcrypto_des.c 351358 2019-08-21 22:42:08Z jhb $");
30184588Sdfr
31184588Sdfr#include <sys/param.h>
32184588Sdfr#include <sys/lock.h>
33184588Sdfr#include <sys/kobj.h>
34184588Sdfr#include <sys/malloc.h>
35184588Sdfr#include <sys/md5.h>
36184588Sdfr#include <sys/mutex.h>
37184588Sdfr#include <sys/mbuf.h>
38184588Sdfr#include <crypto/des/des.h>
39184588Sdfr#include <opencrypto/cryptodev.h>
40184588Sdfr
41184588Sdfr#include <kgssapi/gssapi.h>
42184588Sdfr#include <kgssapi/gssapi_impl.h>
43184588Sdfr
44184588Sdfr#include "kcrypto.h"
45184588Sdfr
46184588Sdfrstruct des1_state {
47184588Sdfr	struct mtx	ds_lock;
48184588Sdfr	uint64_t	ds_session;
49184588Sdfr};
50184588Sdfr
51184588Sdfrstatic void
52184588Sdfrdes1_init(struct krb5_key_state *ks)
53184588Sdfr{
54351243Sjhb	static struct timeval lastwarn;
55184588Sdfr	struct des1_state *ds;
56184588Sdfr
57184588Sdfr	ds = malloc(sizeof(struct des1_state), M_GSSAPI, M_WAITOK|M_ZERO);
58184588Sdfr	mtx_init(&ds->ds_lock, "gss des lock", NULL, MTX_DEF);
59184588Sdfr	ks->ks_priv = ds;
60351358Sjhb	if (ratecheck(&lastwarn, &krb5_warn_interval))
61351243Sjhb		gone_in(13, "DES cipher for Kerberos GSS");
62184588Sdfr}
63184588Sdfr
64184588Sdfrstatic void
65184588Sdfrdes1_destroy(struct krb5_key_state *ks)
66184588Sdfr{
67184588Sdfr	struct des1_state *ds = ks->ks_priv;
68184588Sdfr
69184588Sdfr	if (ds->ds_session)
70184588Sdfr		crypto_freesession(ds->ds_session);
71184588Sdfr	mtx_destroy(&ds->ds_lock);
72184588Sdfr	free(ks->ks_priv, M_GSSAPI);
73184588Sdfr
74184588Sdfr}
75184588Sdfr
76184588Sdfrstatic void
77184588Sdfrdes1_set_key(struct krb5_key_state *ks, const void *in)
78184588Sdfr{
79184588Sdfr	void *kp = ks->ks_key;
80184588Sdfr	struct des1_state *ds = ks->ks_priv;
81184588Sdfr	struct cryptoini cri[1];
82184588Sdfr
83184588Sdfr	if (kp != in)
84184588Sdfr		bcopy(in, kp, ks->ks_class->ec_keylen);
85184588Sdfr
86184588Sdfr	if (ds->ds_session)
87184588Sdfr		crypto_freesession(ds->ds_session);
88184588Sdfr
89184588Sdfr	bzero(cri, sizeof(cri));
90184588Sdfr
91184588Sdfr	cri[0].cri_alg = CRYPTO_DES_CBC;
92184588Sdfr	cri[0].cri_klen = 64;
93184588Sdfr	cri[0].cri_mlen = 0;
94184588Sdfr	cri[0].cri_key = ks->ks_key;
95184588Sdfr	cri[0].cri_next = NULL;
96184588Sdfr
97184588Sdfr	crypto_newsession(&ds->ds_session, cri,
98184588Sdfr	    CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE);
99184588Sdfr}
100184588Sdfr
101184588Sdfrstatic void
102184588Sdfrdes1_random_to_key(struct krb5_key_state *ks, const void *in)
103184588Sdfr{
104184588Sdfr	uint8_t *outkey = ks->ks_key;
105184588Sdfr	const uint8_t *inkey = in;
106184588Sdfr
107184588Sdfr	/*
108184588Sdfr	 * Expand 56 bits of random data to 64 bits as follows
109184588Sdfr	 * (in the example, bit number 1 is the MSB of the 56
110184588Sdfr	 * bits of random data):
111184588Sdfr	 *
112184588Sdfr	 * expanded =
113184588Sdfr	 *	 1  2  3  4  5  6  7  p
114184588Sdfr	 *	 9 10 11 12 13 14 15  p
115184588Sdfr	 *	17 18 19 20 21 22 23  p
116184588Sdfr	 *	25 26 27 28 29 30 31  p
117184588Sdfr	 *	33 34 35 36 37 38 39  p
118184588Sdfr	 *	41 42 43 44 45 46 47  p
119184588Sdfr	 *	49 50 51 52 53 54 55  p
120184588Sdfr	 *	56 48 40 32 24 16  8  p
121184588Sdfr	 */
122184588Sdfr	outkey[0] = inkey[0];
123184588Sdfr	outkey[1] = inkey[1];
124184588Sdfr	outkey[2] = inkey[2];
125184588Sdfr	outkey[3] = inkey[3];
126184588Sdfr	outkey[4] = inkey[4];
127184588Sdfr	outkey[5] = inkey[5];
128184588Sdfr	outkey[6] = inkey[6];
129184588Sdfr	outkey[7] = (((inkey[0] & 1) << 1)
130184588Sdfr	    | ((inkey[1] & 1) << 2)
131184588Sdfr	    | ((inkey[2] & 1) << 3)
132184588Sdfr	    | ((inkey[3] & 1) << 4)
133184588Sdfr	    | ((inkey[4] & 1) << 5)
134184588Sdfr	    | ((inkey[5] & 1) << 6)
135184588Sdfr	    | ((inkey[6] & 1) << 7));
136184588Sdfr	des_set_odd_parity((des_cblock *) outkey);
137184588Sdfr	if (des_is_weak_key((des_cblock *) outkey))
138184588Sdfr		outkey[7] ^= 0xf0;
139184588Sdfr
140184588Sdfr	des1_set_key(ks, ks->ks_key);
141184588Sdfr}
142184588Sdfr
143184588Sdfrstatic int
144184588Sdfrdes1_crypto_cb(struct cryptop *crp)
145184588Sdfr{
146184588Sdfr	int error;
147184588Sdfr	struct des1_state *ds = (struct des1_state *) crp->crp_opaque;
148184588Sdfr
149184588Sdfr	if (CRYPTO_SESID2CAPS(ds->ds_session) & CRYPTOCAP_F_SYNC)
150184588Sdfr		return (0);
151184588Sdfr
152184588Sdfr	error = crp->crp_etype;
153184588Sdfr	if (error == EAGAIN)
154184588Sdfr		error = crypto_dispatch(crp);
155184588Sdfr	mtx_lock(&ds->ds_lock);
156184588Sdfr	if (error || (crp->crp_flags & CRYPTO_F_DONE))
157184588Sdfr		wakeup(crp);
158184588Sdfr	mtx_unlock(&ds->ds_lock);
159184588Sdfr
160184588Sdfr	return (0);
161184588Sdfr}
162184588Sdfr
163184588Sdfrstatic void
164184588Sdfrdes1_encrypt_1(const struct krb5_key_state *ks, int buftype, void *buf,
165184588Sdfr    size_t skip, size_t len, void *ivec, int encdec)
166184588Sdfr{
167184588Sdfr	struct des1_state *ds = ks->ks_priv;
168184588Sdfr	struct cryptop *crp;
169184588Sdfr	struct cryptodesc *crd;
170184588Sdfr	int error;
171184588Sdfr
172184588Sdfr	crp = crypto_getreq(1);
173184588Sdfr	crd = crp->crp_desc;
174184588Sdfr
175184588Sdfr	crd->crd_skip = skip;
176184588Sdfr	crd->crd_len = len;
177184588Sdfr	crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT | encdec;
178184588Sdfr	if (ivec) {
179184588Sdfr		bcopy(ivec, crd->crd_iv, 8);
180184588Sdfr	} else {
181184588Sdfr		bzero(crd->crd_iv, 8);
182184588Sdfr	}
183184588Sdfr	crd->crd_next = NULL;
184184588Sdfr	crd->crd_alg = CRYPTO_DES_CBC;
185184588Sdfr
186184588Sdfr	crp->crp_sid = ds->ds_session;
187184588Sdfr	crp->crp_flags = buftype | CRYPTO_F_CBIFSYNC;
188184588Sdfr	crp->crp_buf = buf;
189184588Sdfr	crp->crp_opaque = (void *) ds;
190184588Sdfr	crp->crp_callback = des1_crypto_cb;
191184588Sdfr
192184588Sdfr	error = crypto_dispatch(crp);
193184588Sdfr
194184588Sdfr	if ((CRYPTO_SESID2CAPS(ds->ds_session) & CRYPTOCAP_F_SYNC) == 0) {
195184588Sdfr		mtx_lock(&ds->ds_lock);
196184588Sdfr		if (!error && !(crp->crp_flags & CRYPTO_F_DONE))
197184588Sdfr			error = msleep(crp, &ds->ds_lock, 0, "gssdes", 0);
198184588Sdfr		mtx_unlock(&ds->ds_lock);
199184588Sdfr	}
200184588Sdfr
201184588Sdfr	crypto_freereq(crp);
202184588Sdfr}
203184588Sdfr
204184588Sdfrstatic void
205184588Sdfrdes1_encrypt(const struct krb5_key_state *ks, struct mbuf *inout,
206184588Sdfr    size_t skip, size_t len, void *ivec, size_t ivlen)
207184588Sdfr{
208184588Sdfr
209184588Sdfr	des1_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec,
210184588Sdfr	    CRD_F_ENCRYPT);
211184588Sdfr}
212184588Sdfr
213184588Sdfrstatic void
214184588Sdfrdes1_decrypt(const struct krb5_key_state *ks, struct mbuf *inout,
215184588Sdfr    size_t skip, size_t len, void *ivec, size_t ivlen)
216184588Sdfr{
217184588Sdfr
218184588Sdfr	des1_encrypt_1(ks, CRYPTO_F_IMBUF, inout, skip, len, ivec, 0);
219184588Sdfr}
220184588Sdfr
221184588Sdfrstatic int
222184588SdfrMD5Update_int(void *ctx, void *buf, u_int len)
223184588Sdfr{
224184588Sdfr
225184588Sdfr	MD5Update(ctx, buf, len);
226184588Sdfr	return (0);
227184588Sdfr}
228184588Sdfr
229184588Sdfrstatic void
230184588Sdfrdes1_checksum(const struct krb5_key_state *ks, int usage,
231184588Sdfr    struct mbuf *inout, size_t skip, size_t inlen, size_t outlen)
232184588Sdfr{
233184588Sdfr	char hash[16];
234184588Sdfr	MD5_CTX md5;
235184588Sdfr
236184588Sdfr	/*
237184588Sdfr	 * This checksum is specifically for GSS-API. First take the
238184588Sdfr	 * MD5 checksum of the message, then calculate the CBC mode
239184588Sdfr	 * checksum of that MD5 checksum using a zero IV.
240184588Sdfr	 */
241184588Sdfr	MD5Init(&md5);
242184588Sdfr	m_apply(inout, skip, inlen, MD5Update_int, &md5);
243184588Sdfr	MD5Final(hash, &md5);
244184588Sdfr
245184588Sdfr	des1_encrypt_1(ks, 0, hash, 0, 16, NULL, CRD_F_ENCRYPT);
246184588Sdfr	m_copyback(inout, skip + inlen, outlen, hash + 8);
247184588Sdfr}
248184588Sdfr
249184588Sdfrstruct krb5_encryption_class krb5_des_encryption_class = {
250184588Sdfr	"des-cbc-md5",		/* name */
251184588Sdfr	ETYPE_DES_CBC_CRC,	/* etype */
252184588Sdfr	0,			/* flags */
253184588Sdfr	8,			/* blocklen */
254184588Sdfr	8,			/* msgblocklen */
255184588Sdfr	8,			/* checksumlen */
256184588Sdfr	56,			/* keybits */
257184588Sdfr	8,			/* keylen */
258184588Sdfr	des1_init,
259184588Sdfr	des1_destroy,
260184588Sdfr	des1_set_key,
261184588Sdfr	des1_random_to_key,
262184588Sdfr	des1_encrypt,
263184588Sdfr	des1_decrypt,
264184588Sdfr	des1_checksum
265184588Sdfr};
266