1/*	$OpenBSD: mppe.c,v 1.15 2019/02/27 04:52:19 denis Exp $ */
2
3/*-
4 * Copyright (c) 2009 Internet Initiative Japan Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28/* $Id: mppe.c,v 1.15 2019/02/27 04:52:19 denis Exp $ */
29/**@file
30 *
31 * The implementation of MPPE(Microsoft Point-To-Point Encryption Protocol)
32 */
33/*
34 * To avoid the PPP packet out of sequence problem.
35 * It may avoid if it reconstruct the frame order in L2TP/IPsec.
36 */
37#define	WORKAROUND_OUT_OF_SEQUENCE_PPP_FRAMING	1
38
39#include <sys/types.h>
40#include <sys/socket.h>
41#include <sys/time.h>
42#include <net/if_dl.h>
43#include <netinet/in.h>
44#include <endian.h>
45#include <stdlib.h>
46#include <stdio.h>
47#include <stdarg.h>
48#include <syslog.h>
49#include <string.h>
50#include <event.h>
51#ifdef	WITH_OPENSSL
52#include <openssl/sha.h>
53#include <openssl/rc4.h>
54#endif
55
56#include "npppd.h"
57#include "debugutil.h"
58
59#ifdef	MPPE_DEBUG
60#define	MPPE_DBG(x)	mppe_log x
61#define	MPPE_ASSERT(x)	\
62	if (!(x)) { \
63	    fprintf(stderr, \
64		"\nASSERT(%s) failed on %s() at %s:%d.\n" \
65		, #x, __func__, __FILE__, __LINE__); \
66	    abort(); \
67	}
68#else
69#define	MPPE_DBG(x)
70#define MPPE_ASSERT(x)
71#endif
72
73#define	SESS_KEY_LEN(len)	(len < 16)?		8 : 16
74
75#define COHER_EQ(a, b) ((((a) - (b)) & 0xfff) == 0)
76#define COHER_LT(a, b) (((int16_t)(((a) - (b)) << 4)) < 0)
77#define COHER_GT(a, b) COHER_LT((b), (a))
78#define COHER_NE(a, b) (!COHER_EQ((a), (b)))
79#define COHER_LE(a, b) (!COHER_GE((b), (a)))
80#define COHER_GE(a, b) (!COHER_LT((a), (b)))
81
82
83static const char  *mppe_bits_to_string(uint32_t);
84static void        mppe_log(mppe *, uint32_t, const char *, ...) __printflike(3,4);
85static int         mppe_rc4_init(mppe *, mppe_rc4_t *, int);
86static int         mppe_rc4_setkey(mppe *, mppe_rc4_t *);
87static int         mppe_rc4_setoldkey(mppe *, mppe_rc4_t *, uint16_t);
88static void        mppe_rc4_destroy(mppe *, mppe_rc4_t *);
89static void        mppe_rc4_encrypt(mppe *, mppe_rc4_t *, int, u_char *, u_char *);
90static void        *rc4_create_ctx(void);
91static int         rc4_key(void *, int, u_char *);
92static void        rc4(void *, int, u_char *, u_char *);
93static void        GetNewKeyFromSHA(u_char *, u_char *, int, u_char *);
94
95/**
96 * initializing mppe context.
97 * 	- reading configuration.
98 */
99void
100mppe_init(mppe *_this, npppd_ppp *ppp)
101{
102	struct tunnconf *conf;
103
104	MPPE_ASSERT(ppp != NULL);
105	MPPE_ASSERT(_this != NULL);
106
107	memset(_this, 0, sizeof(mppe));
108
109	_this->ppp = ppp;
110
111	_this->mode_auto = 1;
112	_this->mode_stateless = 0;
113
114	conf = ppp_get_tunnconf(ppp);
115	_this->enabled = conf->mppe_yesno;
116	if (_this->enabled == 0)
117		goto mppe_config_done;
118
119	_this->required = conf->mppe_required;
120
121	if (conf->mppe_keystate == (NPPPD_MPPE_STATEFUL|NPPPD_MPPE_STATELESS)) {
122		/* no need to change from default. */
123	} else if (conf->mppe_keystate == NPPPD_MPPE_STATELESS) {
124		_this->mode_auto = 0;
125		_this->mode_stateless = 1;
126	} else if (conf->mppe_keystate == NPPPD_MPPE_STATEFUL) {
127		_this->mode_auto = 0;
128		_this->mode_stateless = 0;
129	}
130
131	_this->keylenbits = 0;
132	if ((conf->mppe_keylen & NPPPD_MPPE_40BIT) != 0)
133		_this->keylenbits |= CCP_MPPE_NT_40bit;
134	if ((conf->mppe_keylen & NPPPD_MPPE_56BIT) != 0)
135		_this->keylenbits |= CCP_MPPE_NT_56bit;
136	if ((conf->mppe_keylen & NPPPD_MPPE_128BIT) != 0)
137		_this->keylenbits |= CCP_MPPE_NT_128bit;
138
139mppe_config_done:
140	/* nothing */;
141}
142
143void
144mppe_fini(mppe *_this)
145{
146	mppe_rc4_destroy(_this, &_this->send);
147	mppe_rc4_destroy(_this, &_this->recv);
148}
149
150static void
151mppe_reduce_key(mppe_rc4_t *_this)
152{
153	switch (_this->keybits) {
154	case 40:
155		_this->session_key[1] = 0x26;
156		_this->session_key[2] = 0x9e;
157	case 56:
158		_this->session_key[0] = 0xd1;
159	}
160}
161
162static void
163mppe_key_change(mppe *_mppe, mppe_rc4_t *_this)
164{
165	u_char interim[16];
166	void *keychg;
167
168	keychg = rc4_create_ctx();
169
170	GetNewKeyFromSHA(_this->master_key, _this->session_key,
171	    _this->keylen, interim);
172
173	rc4_key(keychg, _this->keylen, interim);
174	rc4(keychg, _this->keylen, interim, _this->session_key);
175	mppe_reduce_key(_this);
176
177	if (_this->old_session_keys) {
178		int idx = _this->coher_cnt % MPPE_NOLDKEY;
179		memcpy(_this->old_session_keys[idx],
180		    _this->session_key, MPPE_KEYLEN);
181	}
182
183	free(keychg);
184}
185
186/**
187 * starting mppe protocol.
188 */
189void
190mppe_start(mppe *_this)
191{
192	char buf[256];
193
194	strlcpy(buf, mppe_bits_to_string(_this->ppp->ccp.mppe_o_bits),
195	    sizeof(buf));
196
197	mppe_log(_this, LOG_INFO, "logtype=Opened our=%s peer=%s", buf,
198	    mppe_bits_to_string(_this->ppp->ccp.mppe_p_bits));
199
200	_this->ppp->mppe_started = 1;
201
202	_this->send.stateless =
203	    ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_STATELESS) != 0)? 1 : 0;
204
205	if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_40bit) != 0) {
206		_this->send.keylen = 8;
207		_this->send.keybits = 40;
208	} else if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_56bit) != 0) {
209		_this->send.keylen = 8;
210		_this->send.keybits = 56;
211	} else if ((_this->ppp->ccp.mppe_o_bits & CCP_MPPE_NT_128bit) != 0) {
212		_this->send.keylen = 16;
213		_this->send.keybits = 128;
214	}
215
216	_this->recv.stateless =
217	    ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_STATELESS) != 0)? 1 : 0;
218	if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_40bit) != 0) {
219		_this->recv.keylen = 8;
220		_this->recv.keybits = 40;
221	} else if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_56bit) != 0) {
222		_this->recv.keylen = 8;
223		_this->recv.keybits = 56;
224	} else if ((_this->ppp->ccp.mppe_p_bits & CCP_MPPE_NT_128bit) != 0) {
225		_this->recv.keylen = 16;
226		_this->recv.keybits = 128;
227	}
228
229	if (_this->send.keybits > 0) {
230		mppe_rc4_init(_this, &_this->send, 0);
231		GetNewKeyFromSHA(_this->send.master_key, _this->send.master_key,
232		    _this->send.keylen, _this->send.session_key);
233		mppe_reduce_key(&_this->send);
234		mppe_rc4_setkey(_this, &_this->send);
235	}
236	if (_this->recv.keybits > 0) {
237		mppe_rc4_init(_this, &_this->recv, _this->recv.stateless);
238		GetNewKeyFromSHA(_this->recv.master_key, _this->recv.master_key,
239		    _this->recv.keylen, _this->recv.session_key);
240		mppe_reduce_key(&_this->recv);
241		mppe_rc4_setkey(_this, &_this->recv);
242	}
243}
244
245/**
246 * creating the mppe bits. In case of first proposal, it specifies the
247 * peer_bits as 0 value. If it specifies the peer_bits, it returns the
248 * value as peer's proposal.
249 */
250uint32_t
251mppe_create_our_bits(mppe *_this, uint32_t peer_bits)
252{
253	uint32_t our_bits;
254
255	/* default proposal */
256	our_bits = _this->keylenbits;
257	if (peer_bits != 0 && (peer_bits & our_bits) != 0) {
258		if ((peer_bits & CCP_MPPE_NT_128bit) != 0)
259			our_bits = CCP_MPPE_NT_128bit;
260		else if ((peer_bits & CCP_MPPE_NT_56bit) != 0)
261			our_bits = CCP_MPPE_NT_56bit;
262		else if ((peer_bits & CCP_MPPE_NT_40bit) != 0)
263			our_bits = CCP_MPPE_NT_40bit;
264	}
265
266	if (_this->mode_auto != 0) {
267		/* in case of auto_mode */
268		if (peer_bits == 0) {
269			/*
270			 * It proposes stateless mode in first time. Windows 9x has
271			 * a bug that it is reverse to stateful and stateless in
272			 * sending and receiving packets.
273			 * Windows 9x is prior to negotiate in stateless mode, so
274			 * it will avoid the Windows bug to be prior to negotiate
275			 * in stateless mode.
276			 *
277			 * Even if this bug doesn't exists, the stateful mode is high
278			 * cost from user's viewpoint when packets may loss more than a
279			 * certain rate, so it is not good choice to use via Internet or
280			 * wireless LAN.
281			 */
282			our_bits |= CCP_MPPE_STATELESS;
283		} else {
284			/* giving up */
285			our_bits |= peer_bits & CCP_MPPE_STATELESS;
286		}
287	} else {
288		/* it doesn't give up in case of setting non-auto value. */
289		if (_this->mode_stateless != 0)
290			our_bits |= CCP_MPPE_STATELESS;
291	}
292	if (peer_bits != 0 && our_bits != peer_bits) {
293		char obuf[128], pbuf[128];
294
295		/* in case of failure, it puts a log. */
296		strlcpy(obuf, mppe_bits_to_string(our_bits), sizeof(obuf));
297		strlcpy(pbuf, mppe_bits_to_string(peer_bits), sizeof(pbuf));
298		mppe_log(_this, LOG_INFO,
299		    "mismatch our=%s peer=%s", obuf, pbuf);
300	}
301
302	return our_bits;
303}
304
305#define	COHERENCY_CNT_MASK	0x0fff;
306
307/**
308 * receiving packets via MPPE.
309 * len must be 4 at least.
310 */
311void
312mppe_input(mppe *_this, u_char *pktp, int len)
313{
314	int pktloss, encrypt, flushed, m, n;
315	uint16_t coher_cnt;
316	u_char *pktp0, *opktp, *opktp0;
317	uint16_t proto;
318	int delayed = 0;
319
320	encrypt = 0;
321	flushed = 0;
322
323	MPPE_ASSERT(len >= 4);
324
325	pktp0 = pktp;
326	GETSHORT(coher_cnt, pktp);
327
328	flushed = (coher_cnt & 0x8000)? 1 : 0;
329	encrypt = (coher_cnt & 0x1000)? 1 : 0;
330	coher_cnt &= COHERENCY_CNT_MASK;
331	pktloss = 0;
332
333	MPPE_DBG((_this, DEBUG_LEVEL_2, "in coher_cnt=%03x/%03x %s%s",
334	    _this->recv.coher_cnt, coher_cnt, (flushed)? "[flushed]" : "",
335	    (encrypt)? "[encrypt]" : ""));
336
337	if (encrypt == 0) {
338		mppe_log(_this, LOG_WARNING,
339		    "Received unexpected MPPE packet.  (no encrypt)");
340		return;
341	}
342
343	/*
344	 * In L2TP/IPsec implementation, in case that the ppp frame sequence
345	 * is not able to reconstruct and the ppp frame is out of sequence, it
346	 * is unable to identify with many packets losing. If it does so, MPPE
347	 * key is out of place.
348	 * To avoid this problem, when it seems that more than 4096-256 packets
349	 * drops, it assumes that the packet doesn't lose but the packet is out
350	 * of sequence.
351	 */
352    {
353	int coher_cnt0;
354
355	coher_cnt0 = coher_cnt;
356	if (coher_cnt < _this->recv.coher_cnt)
357		coher_cnt0 += 0x1000;
358	if (coher_cnt0 - _this->recv.coher_cnt > 0x0f00) {
359		if (!_this->recv.stateless ||
360		    coher_cnt0 - _this->recv.coher_cnt
361		    <= 0x1000 - MPPE_NOLDKEY) {
362			mppe_log(_this, LOG_INFO,
363			    "Workaround the out-of-sequence PPP framing problem: "
364			    "%d => %d", _this->recv.coher_cnt, coher_cnt);
365			return;
366		}
367		delayed = 1;
368	}
369    }
370
371	if (_this->recv.stateless != 0) {
372		if (!delayed) {
373			mppe_key_change(_this, &_this->recv);
374			while (_this->recv.coher_cnt != coher_cnt) {
375				_this->recv.coher_cnt++;
376				_this->recv.coher_cnt &= COHERENCY_CNT_MASK;
377				mppe_key_change(_this, &_this->recv);
378				pktloss++;
379			}
380		}
381		mppe_rc4_setoldkey(_this, &_this->recv, coher_cnt);
382		flushed = 1;
383	} else {
384		if (flushed) {
385			if (coher_cnt < _this->recv.coher_cnt) {
386				/* in case of carrying up. */
387				coher_cnt += 0x1000;
388			}
389			pktloss += coher_cnt - _this->recv.coher_cnt;
390			m = _this->recv.coher_cnt / 256;
391			n = coher_cnt / 256;
392			while (m++ < n)
393				mppe_key_change(_this, &_this->recv);
394
395			coher_cnt &= COHERENCY_CNT_MASK;
396			_this->recv.coher_cnt = coher_cnt;
397		} else if (_this->recv.coher_cnt != coher_cnt) {
398			_this->recv.resetreq = 1;
399
400			opktp0 = ppp_packetbuf(_this->ppp,
401			    PPP_PROTO_NCP | NCP_CCP);
402			opktp = opktp0;
403
404			PUTLONG(_this->ppp->ccp.mppe_p_bits, opktp);
405
406			ppp_output(_this->ppp, PPP_PROTO_NCP | NCP_CCP,
407			    RESETREQ, _this->recv.resetreq, opktp0,
408				opktp - opktp0);
409			return;
410		}
411		if ((coher_cnt & 0xff) == 0xff) {
412			mppe_key_change(_this, &_this->recv);
413			flushed = 1;
414		}
415		if (flushed) {
416			mppe_rc4_setkey(_this, &_this->recv);
417		}
418	}
419
420	if (pktloss > 1000) {
421		/*
422		 * In case of many packets losing or out of sequence.
423		 * The latter is not able to communicate because the key is
424		 * out of place soon.
425		 *
426		 */
427		mppe_log(_this, LOG_WARNING, "%d packets loss", pktloss);
428	}
429
430	mppe_rc4_encrypt(_this, &_this->recv, len - 2, pktp, pktp);
431
432	if (!delayed) {
433		_this->recv.coher_cnt++;
434		_this->recv.coher_cnt &= COHERENCY_CNT_MASK;
435	}
436
437	if (pktp[0] & 1)
438		proto = pktp[0];
439	else
440		proto = pktp[0] << 8 | pktp[1];
441	/*
442	 * According to RFC3078 section 3,
443	 * MPPE only accept protocol number 0021-00FA.
444	 * If decrypted protocol number is out of range,
445	 * it indicates loss of coherency.
446	 */
447	if (!(proto & 1) || proto < 0x21 || proto > 0xfa) {
448		mppe_log(_this, LOG_INFO, "MPPE coherency is lost");
449		return; /* drop frame */
450	}
451
452	_this->ppp->recv_packet(_this->ppp, pktp, len - 2,
453	    PPP_IO_FLAGS_MPPE_ENCRYPTED);
454}
455
456/**
457 * The call out function in case of receiving CCP Reset (key reset in case
458 * of MPPE).
459 */
460void
461mppe_recv_ccp_reset(mppe *_this)
462{
463	MPPE_DBG((_this, DEBUG_LEVEL_2, "%s() is called.", __func__));
464	_this->send.resetreq = 1;
465}
466
467/**
468 * sending packet via MPPE.
469 */
470void
471mppe_pkt_output(mppe *_this, uint16_t proto, u_char *pktp, int len)
472{
473	int encrypt, flushed;
474	uint16_t coher_cnt;
475	u_char *outp, *outp0;
476
477	MPPE_ASSERT(proto == PPP_PROTO_IP);
478
479	flushed = 0;
480	encrypt = 1;
481
482	outp = ppp_packetbuf(_this->ppp, PPP_PROTO_MPPE);
483	outp0 = outp;
484
485	if (_this->send.stateless != 0) {
486		flushed = 1;
487		mppe_key_change(_this, &_this->send);
488	} else {
489		if ((_this->send.coher_cnt % 0x100) == 0xff) {
490			flushed = 1;
491			mppe_key_change(_this, &_this->send);
492		} else if (_this->send.resetreq != 0) {
493			flushed = 1;
494			_this->send.resetreq = 0;
495		}
496	}
497
498	if (flushed) {
499		mppe_rc4_setkey(_this, &_this->send);
500	}
501
502	MPPE_DBG((_this, DEBUG_LEVEL_2, "out coher_cnt=%03x %s%s",
503	    _this->send.coher_cnt, (flushed)? "[flushed]" : "",
504	    (encrypt)? "[encrypt]" : ""));
505
506	coher_cnt = _this->send.coher_cnt & COHERENCY_CNT_MASK;
507	if (flushed)
508		coher_cnt |= 0x8000;
509	if (encrypt)
510		coher_cnt |= 0x1000;
511
512	PUTSHORT(coher_cnt, outp);
513	proto = htons(proto);
514	mppe_rc4_encrypt(_this, &_this->send, 2, (u_char *)&proto, outp);
515	mppe_rc4_encrypt(_this, &_this->send, len, pktp, outp + 2);
516
517	ppp_output(_this->ppp, PPP_PROTO_MPPE, 0, 0, outp0, len + 4);
518	_this->send.coher_cnt++;
519	_this->send.coher_cnt &= COHERENCY_CNT_MASK;
520}
521
522static void
523mppe_log(mppe *_this, uint32_t prio, const char *fmt, ...)
524{
525	char logbuf[BUFSIZ];
526	va_list ap;
527
528	va_start(ap, fmt);
529	snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=mppe %s",
530	    _this->ppp->id, fmt);
531	vlog_printf(prio, logbuf, ap);
532	va_end(ap);
533}
534
535static const char *
536mppe_bits_to_string(uint32_t bits)
537{
538	static char buf[128];
539
540	snprintf(buf, sizeof(buf), "%s%s%s%s%s%s"
541	, ((CCP_MPPC_ALONE & bits) != 0)?	",mppc" : ""
542	, ((CCP_MPPE_LM_40bit& bits) != 0)?	",40bit(LM)" : ""
543	, ((CCP_MPPE_NT_40bit& bits) != 0)?	",40bit" : ""
544	, ((CCP_MPPE_NT_128bit& bits) != 0)?	",128bit" : ""
545	, ((CCP_MPPE_NT_56bit& bits) != 0)?	",56bit" : ""
546	, ((CCP_MPPE_STATELESS& bits) != 0)?	",stateless" : ",stateful");
547
548	if (buf[0] == '\0')
549		return "";
550
551	return buf + 1;
552}
553
554/************************************************************************
555 * implementations of authentication/cipher algorism.
556 ************************************************************************/
557static u_char SHAPad1[] = {
558	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
563}, SHAPad2[] = {
564	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
565	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
566	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
567	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
568	0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
569};
570#define	ZeroMemory(dst, len)		memset(dst, 0, len)
571#define	MoveMemory(dst, src, len)	memcpy(dst, src, len)
572
573#include <openssl/rc4.h>
574#include <openssl/sha.h>
575
576#define	SHA_CTX			SHA_CTX
577#define	SHAInit			SHA1_Init
578#define	SHAUpdate		SHA1_Update
579#define	SHAFinal(ctx,digest)	SHA1_Final(digest, ctx)
580
581/************************************************************************
582 * implementations of OpenSSL version
583 ************************************************************************/
584static void *
585rc4_create_ctx(void)
586{
587	return malloc(sizeof(RC4_KEY));
588}
589
590static int
591rc4_key(void *rc4ctx, int lkey, u_char *key)
592{
593
594	RC4_set_key(rc4ctx, lkey, key);
595
596	return 0;
597}
598
599static void
600rc4(void *rc4ctx, int len, u_char *indata, u_char *outdata)
601{
602	RC4(rc4ctx, len, indata, outdata);
603}
604
605static void
606GetNewKeyFromSHA(u_char *StartKey, u_char *SessionKey, int SessionKeyLength,
607    u_char *InterimKey)
608{
609	u_char Digest[20];
610	SHA_CTX Context;
611
612	ZeroMemory(Digest, 20);
613
614	SHAInit(&Context);
615	SHAUpdate(&Context, StartKey, SessionKeyLength);
616	SHAUpdate(&Context, SHAPad1, 40);
617	SHAUpdate(&Context, SessionKey, SessionKeyLength);
618	SHAUpdate(&Context, SHAPad2, 40);
619	SHAFinal(&Context, Digest);
620
621	MoveMemory(InterimKey, Digest, SessionKeyLength);
622}
623
624static int
625mppe_rc4_init(mppe *_mppe, mppe_rc4_t *_this, int has_oldkey)
626{
627	if ((_this->rc4ctx = rc4_create_ctx()) == NULL) {
628		mppe_log(_mppe, LOG_ERR, "malloc() failed at %s: %m",
629		    __func__);
630		return 1;
631	}
632
633	if (has_oldkey)
634		_this->old_session_keys = reallocarray(NULL,
635		    MPPE_KEYLEN, MPPE_NOLDKEY);
636	else
637		_this->old_session_keys = NULL;
638
639	return 0;
640}
641
642static int
643mppe_rc4_setkey(mppe *_mppe, mppe_rc4_t *_this)
644{
645	return rc4_key(_this->rc4ctx, _this->keylen, _this->session_key);
646}
647
648static int
649mppe_rc4_setoldkey(mppe *_mppe, mppe_rc4_t *_this, uint16_t coher_cnt)
650{
651	return rc4_key(_this->rc4ctx, _this->keylen,
652	    _this->old_session_keys[coher_cnt % MPPE_NOLDKEY]);
653}
654
655static void
656mppe_rc4_encrypt(mppe *_mppe, mppe_rc4_t *_this, int len, u_char *indata, u_char *outdata)
657{
658	rc4(_this->rc4ctx, len, indata, outdata);
659}
660
661static void
662mppe_rc4_destroy(mppe *_mppe, mppe_rc4_t *_this)
663{
664	free(_this->rc4ctx);
665	free(_this->old_session_keys);
666	_this->rc4ctx = NULL;
667}
668