⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ppp_mppe.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * ppp_mppe.c - interface MPPE to the PPP code. * This version is for use with Linux kernel 2.6.14+ * * By Frank Cusack <fcusack@fcusack.com>. * Copyright (c) 2002,2003,2004 Google, Inc. * All rights reserved. * * License: * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies.  This software is provided without any * warranty, express or implied. * * ALTERNATIVELY, provided that this notice is retained in full, this product * may be distributed under the terms of the GNU General Public License (GPL), * in which case the provisions of the GPL apply INSTEAD OF those given above. * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * * Changelog: *      08/12/05 - Matt Domsch <Matt_Domsch@dell.com> *                 Only need extra skb padding on transmit, not receive. *      06/18/04 - Matt Domsch <Matt_Domsch@dell.com>, Oleg Makarenko <mole@quadra.ru> *                 Use Linux kernel 2.6 arc4 and sha1 routines rather than *                 providing our own. *      2/15/04 - TS: added #include <version.h> and testing for Kernel *                    version before using *                    MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are *                    deprecated in 2.6 */#include <linux/err.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/init.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/crypto.h>#include <linux/mm.h>#include <linux/ppp_defs.h>#include <linux/ppp-comp.h>#include <linux/scatterlist.h>#include "ppp_mppe.h"MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>");MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");MODULE_LICENSE("Dual BSD/GPL");MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));MODULE_VERSION("1.0.2");static unsigned intsetup_sg(struct scatterlist *sg, const void *address, unsigned int length){	sg_set_buf(sg, address, length);	return length;}#define SHA1_PAD_SIZE 40/* * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module * static data area.  That means sha_pad needs to be kmalloc'd. */struct sha_pad {	unsigned char sha_pad1[SHA1_PAD_SIZE];	unsigned char sha_pad2[SHA1_PAD_SIZE];};static struct sha_pad *sha_pad;static inline void sha_pad_init(struct sha_pad *shapad){	memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1));	memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2));}/* * State for an MPPE (de)compressor. */struct ppp_mppe_state {	struct crypto_blkcipher *arc4;	struct crypto_hash *sha1;	unsigned char *sha1_digest;	unsigned char master_key[MPPE_MAX_KEY_LEN];	unsigned char session_key[MPPE_MAX_KEY_LEN];	unsigned keylen;	/* key length in bytes             */	/* NB: 128-bit == 16, 40-bit == 8! */	/* If we want to support 56-bit,   */	/* the unit has to change to bits  */	unsigned char bits;	/* MPPE control bits */	unsigned ccount;	/* 12-bit coherency count (seqno)  */	unsigned stateful;	/* stateful mode flag */	int discard;		/* stateful mode packet loss flag */	int sanity_errors;	/* take down LCP if too many */	int unit;	int debug;	struct compstat stats;};/* struct ppp_mppe_state.bits definitions */#define MPPE_BIT_A	0x80	/* Encryption table were (re)inititalized */#define MPPE_BIT_B	0x40	/* MPPC only (not implemented) */#define MPPE_BIT_C	0x20	/* MPPC only (not implemented) */#define MPPE_BIT_D	0x10	/* This is an encrypted frame */#define MPPE_BIT_FLUSHED	MPPE_BIT_A#define MPPE_BIT_ENCRYPTED	MPPE_BIT_D#define MPPE_BITS(p) ((p)[4] & 0xf0)#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5])#define MPPE_CCOUNT_SPACE 0x1000	/* The size of the ccount space */#define MPPE_OVHD	2	/* MPPE overhead/packet */#define SANITY_MAX	1600	/* Max bogon factor we will tolerate *//* * Key Derivation, from RFC 3078, RFC 3079. * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. */static void get_new_key_from_sha(struct ppp_mppe_state * state){	struct hash_desc desc;	struct scatterlist sg[4];	unsigned int nbytes;	sg_init_table(sg, 4);	nbytes = setup_sg(&sg[0], state->master_key, state->keylen);	nbytes += setup_sg(&sg[1], sha_pad->sha_pad1,			   sizeof(sha_pad->sha_pad1));	nbytes += setup_sg(&sg[2], state->session_key, state->keylen);	nbytes += setup_sg(&sg[3], sha_pad->sha_pad2,			   sizeof(sha_pad->sha_pad2));	desc.tfm = state->sha1;	desc.flags = 0;	crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest);}/* * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. * Well, not what's written there, but rather what they meant. */static void mppe_rekey(struct ppp_mppe_state * state, int initial_key){	struct scatterlist sg_in[1], sg_out[1];	struct blkcipher_desc desc = { .tfm = state->arc4 };	get_new_key_from_sha(state);	if (!initial_key) {		crypto_blkcipher_setkey(state->arc4, state->sha1_digest,					state->keylen);		sg_init_table(sg_in, 1);		sg_init_table(sg_out, 1);		setup_sg(sg_in, state->sha1_digest, state->keylen);		setup_sg(sg_out, state->session_key, state->keylen);		if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,					     state->keylen) != 0) {    		    printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");		}	} else {		memcpy(state->session_key, state->sha1_digest, state->keylen);	}	if (state->keylen == 8) {		/* See RFC 3078 */		state->session_key[0] = 0xd1;		state->session_key[1] = 0x26;		state->session_key[2] = 0x9e;	}	crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen);}/* * Allocate space for a (de)compressor. */static void *mppe_alloc(unsigned char *options, int optlen){	struct ppp_mppe_state *state;	unsigned int digestsize;	if (optlen != CILEN_MPPE + sizeof(state->master_key)	    || options[0] != CI_MPPE || options[1] != CILEN_MPPE)		goto out;	state = kzalloc(sizeof(*state), GFP_KERNEL);	if (state == NULL)		goto out;	state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);	if (IS_ERR(state->arc4)) {		state->arc4 = NULL;		goto out_free;	}	state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);	if (IS_ERR(state->sha1)) {		state->sha1 = NULL;		goto out_free;	}	digestsize = crypto_hash_digestsize(state->sha1);	if (digestsize < MPPE_MAX_KEY_LEN)		goto out_free;	state->sha1_digest = kmalloc(digestsize, GFP_KERNEL);	if (!state->sha1_digest)		goto out_free;	/* Save keys. */	memcpy(state->master_key, &options[CILEN_MPPE],	       sizeof(state->master_key));	memcpy(state->session_key, state->master_key,	       sizeof(state->master_key));	/*	 * We defer initial key generation until mppe_init(), as mppe_alloc()	 * is called frequently during negotiation.	 */	return (void *)state;	out_free:	    if (state->sha1_digest)		kfree(state->sha1_digest);	    if (state->sha1)		crypto_free_hash(state->sha1);	    if (state->arc4)		crypto_free_blkcipher(state->arc4);	    kfree(state);	out:	return NULL;}/* * Deallocate space for a (de)compressor. */static void mppe_free(void *arg){	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;	if (state) {	    if (state->sha1_digest)		kfree(state->sha1_digest);	    if (state->sha1)		crypto_free_hash(state->sha1);	    if (state->arc4)		crypto_free_blkcipher(state->arc4);	    kfree(state);	}}/* * Initialize (de)compressor state. */static intmppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug,	  const char *debugstr){	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;	unsigned char mppe_opts;	if (optlen != CILEN_MPPE	    || options[0] != CI_MPPE || options[1] != CILEN_MPPE)		return 0;	MPPE_CI_TO_OPTS(&options[2], mppe_opts);	if (mppe_opts & MPPE_OPT_128)		state->keylen = 16;	else if (mppe_opts & MPPE_OPT_40)		state->keylen = 8;	else {		printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr,		       unit);		return 0;	}	if (mppe_opts & MPPE_OPT_STATEFUL)		state->stateful = 1;	/* Generate the initial session key. */	mppe_rekey(state, 1);	if (debug) {		int i;		char mkey[sizeof(state->master_key) * 2 + 1];		char skey[sizeof(state->session_key) * 2 + 1];		printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n",		       debugstr, unit, (state->keylen == 16) ? 128 : 40,		       (state->stateful) ? "stateful" : "stateless");		for (i = 0; i < sizeof(state->master_key); i++)			sprintf(mkey + i * 2, "%02x", state->master_key[i]);		for (i = 0; i < sizeof(state->session_key); i++)			sprintf(skey + i * 2, "%02x", state->session_key[i]);		printk(KERN_DEBUG		       "%s[%d]: keys: master: %s initial session: %s\n",		       debugstr, unit, mkey, skey);	}	/*	 * Initialize the coherency count.  The initial value is not specified	 * in RFC 3078, but we can make a reasonable assumption that it will	 * start at 0.  Setting it to the max here makes the comp/decomp code	 * do the right thing (determined through experiment).	 */	state->ccount = MPPE_CCOUNT_SPACE - 1;	/*	 * Note that even though we have initialized the key table, we don't	 * set the FLUSHED bit.  This is contrary to RFC 3078, sec. 3.1.	 */	state->bits = MPPE_BIT_ENCRYPTED;	state->unit = unit;	state->debug = debug;	return 1;}static intmppe_comp_init(void *arg, unsigned char *options, int optlen, int unit,	       int hdrlen, int debug){	/* ARGSUSED */	return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init");}/* * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), * tell the compressor to rekey.  Note that we MUST NOT rekey for * every CCP Reset-Request; we only rekey on the next xmit packet. * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. * So, rekeying for every CCP Reset-Request is broken as the peer will not * know how many times we've rekeyed.  (If we rekey and THEN get another * CCP Reset-Request, we must rekey again.) */static void mppe_comp_reset(void *arg){	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;	state->bits |= MPPE_BIT_FLUSHED;}/* * Compress (encrypt) a packet. * It's strange to call this a compressor, since the output is always * MPPE_OVHD + 2 bytes larger than the input. */static intmppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,	      int isize, int osize){	struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;	struct blkcipher_desc desc = { .tfm = state->arc4 };

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -