esp_core.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,150 行 · 第 1/2 页

C
1,150
字号
static intesp_3des_schedule(algo, sav)	const struct esp_algorithm *algo;	struct secasvar *sav;{	int error;	des_key_schedule *p;	int i;	char *k;	p = (des_key_schedule *)sav->sched;	k = _KEYBUF(sav->key_enc);	for (i = 0; i < 3; i++) {		error = des_key_sched((des_cblock *)(k + 8 * i), p[i]);		if (error)			return EINVAL;	}	return 0;}static intesp_3des_blockdecrypt(algo, sav, s, d)	const struct esp_algorithm *algo;	struct secasvar *sav;	u_int8_t *s;	u_int8_t *d;{	des_key_schedule *p;	/* assumption: d has a good alignment */	p = (des_key_schedule *)sav->sched;	bcopy(s, d, sizeof(DES_LONG) * 2);	des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, 			 p[0], p[1], p[2], DES_DECRYPT);	return 0;}static intesp_3des_blockencrypt(algo, sav, s, d)	const struct esp_algorithm *algo;	struct secasvar *sav;	u_int8_t *s;	u_int8_t *d;{	des_key_schedule *p;	/* assumption: d has a good alignment */	p = (des_key_schedule *)sav->sched;	bcopy(s, d, sizeof(DES_LONG) * 2);	des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, 			 p[0], p[1], p[2], DES_ENCRYPT);	return 0;}static intesp_common_ivlen(algo, sav)	const struct esp_algorithm *algo;	struct secasvar *sav;{	if (!algo)		panic("esp_common_ivlen: unknown algorithm");	return algo->ivlenval;}static intesp_cbc_decrypt(m, off, sav, algo, ivlen)	struct mbuf *m;	size_t off;	struct secasvar *sav;	const struct esp_algorithm *algo;	int ivlen;{	struct mbuf *s;	struct mbuf *d, *d0, *dp;	int soff, doff;	/* offset from the head of chain, to head of this mbuf */	int sn, dn;	/* offset from the head of the mbuf, to meat */	size_t ivoff, bodyoff;	u_int8_t iv[MAXIVLEN], *ivp;	u_int8_t sbuf[MAXIVLEN], *sp;	u_int8_t *p, *q;	struct mbuf *scut;	int scutoff;	int i;	int blocklen;	int derived;	if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {		ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "		    "unsupported ivlen %d\n", algo->name, ivlen));		m_freem(m);		return EINVAL;	}	/* assumes blocklen == padbound */	blocklen = algo->padbound;#ifdef DIAGNOSTIC	if (blocklen > sizeof(iv)) {		ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "		    "unsupported blocklen %d\n", algo->name, blocklen));		m_freem(m);		return EINVAL;	}#endif	if (sav->flags & SADB_X_EXT_OLD) {		/* RFC 1827 */		ivoff = off + sizeof(struct esp);		bodyoff = off + sizeof(struct esp) + ivlen;		derived = 0;	} else {		/* RFC 2406 */		if (sav->flags & SADB_X_EXT_DERIV) {			/*			 * draft-ietf-ipsec-ciph-des-derived-00.txt			 * uses sequence number field as IV field.			 */			ivoff = off + sizeof(struct esp);			bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);			ivlen = sizeof(u_int32_t);			derived = 1;		} else {			ivoff = off + sizeof(struct newesp);			bodyoff = off + sizeof(struct newesp) + ivlen;			derived = 0;		}	}	/* grab iv */	m_copydata(m, ivoff, ivlen, iv);	/* extend iv */	if (ivlen == blocklen)		;	else if (ivlen == 4 && blocklen == 8) {		bcopy(&iv[0], &iv[4], 4);		iv[4] ^= 0xff;		iv[5] ^= 0xff;		iv[6] ^= 0xff;		iv[7] ^= 0xff;	} else {		ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "		    "unsupported ivlen/blocklen: %d %d\n",		    algo->name, ivlen, blocklen));		m_freem(m);		return EINVAL;	}	if (m->m_pkthdr.len < bodyoff) {		ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n",		    algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));		m_freem(m);		return EINVAL;	}	if ((m->m_pkthdr.len - bodyoff) % blocklen) {		ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "		    "payload length must be multiple of %d\n",		    algo->name, blocklen));		m_freem(m);		return EINVAL;	}	s = m;	d = d0 = dp = NULL;	soff = doff = sn = dn = 0;	ivp = sp = NULL;	/* skip bodyoff */	while (soff < bodyoff) {		if (soff + s->m_len > bodyoff) {			sn = bodyoff - soff;			break;		}		soff += s->m_len;		s = s->m_next;	}	scut = s;	scutoff = sn;	/* skip over empty mbuf */	while (s && s->m_len == 0)		s = s->m_next;	while (soff < m->m_pkthdr.len) {		/* source */		if (sn + blocklen <= s->m_len) {			/* body is continuous */			sp = mtod(s, u_int8_t *) + sn;		} else {			/* body is non-continuous */			m_copydata(s, sn, blocklen, sbuf);			sp = sbuf;		}		/* destination */		if (!d || dn + blocklen > d->m_len) {			if (d)				dp = d;			MGET(d, M_DONTWAIT, MT_DATA);			i = m->m_pkthdr.len - (soff + sn);			if (d && i > MLEN) {				MCLGET(d, M_DONTWAIT);				if ((d->m_flags & M_EXT) == 0) {					m_free(d);					d = NULL;				}			}			if (!d) {				m_freem(m);				if (d0)					m_freem(d0);				return ENOBUFS;			}			if (!d0)				d0 = d;			if (dp)				dp->m_next = d;			d->m_len = 0;			d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;			if (d->m_len > i)				d->m_len = i;			dn = 0;		}		/* decrypt */		(*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);		/* xor */		p = ivp ? ivp : iv;		q = mtod(d, u_int8_t *) + dn;		for (i = 0; i < blocklen; i++)			q[i] ^= p[i];		/* next iv */		if (sp == sbuf) {			bcopy(sbuf, iv, blocklen);			ivp = NULL;		} else			ivp = sp;		sn += blocklen;		dn += blocklen;		/* find the next source block */		while (s && sn >= s->m_len) {			sn -= s->m_len;			soff += s->m_len;			s = s->m_next;		}		/* skip over empty mbuf */		while (s && s->m_len == 0)			s = s->m_next;	}	m_freem(scut->m_next);	scut->m_len = scutoff;	scut->m_next = d0;	/* just in case */	bzero(iv, sizeof(iv));	bzero(sbuf, sizeof(sbuf));	return 0;}static intesp_cbc_encrypt(m, off, plen, sav, algo, ivlen)	struct mbuf *m;	size_t off;	size_t plen;	struct secasvar *sav;	const struct esp_algorithm *algo;	int ivlen;{	struct mbuf *s;	struct mbuf *d, *d0, *dp;	int soff, doff;	/* offset from the head of chain, to head of this mbuf */	int sn, dn;	/* offset from the head of the mbuf, to meat */	size_t ivoff, bodyoff;	u_int8_t iv[MAXIVLEN], *ivp;	u_int8_t sbuf[MAXIVLEN], *sp;	u_int8_t *p, *q;	struct mbuf *scut;	int scutoff;	int i;	int blocklen;	int derived;	if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {		ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "		    "unsupported ivlen %d\n", algo->name, ivlen));		m_freem(m);		return EINVAL;	}	/* assumes blocklen == padbound */	blocklen = algo->padbound;#ifdef DIAGNOSTIC	if (blocklen > sizeof(iv)) {		ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "		    "unsupported blocklen %d\n", algo->name, blocklen));		m_freem(m);		return EINVAL;	}#endif	if (sav->flags & SADB_X_EXT_OLD) {		/* RFC 1827 */		ivoff = off + sizeof(struct esp);		bodyoff = off + sizeof(struct esp) + ivlen;		derived = 0;	} else {		/* RFC 2406 */		if (sav->flags & SADB_X_EXT_DERIV) {			/*			 * draft-ietf-ipsec-ciph-des-derived-00.txt			 * uses sequence number field as IV field.			 */			ivoff = off + sizeof(struct esp);			bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);			ivlen = sizeof(u_int32_t);			derived = 1;		} else {			ivoff = off + sizeof(struct newesp);			bodyoff = off + sizeof(struct newesp) + ivlen;			derived = 0;		}	}	/* put iv into the packet.  if we are in derived mode, use seqno. */	if (derived)		m_copydata(m, ivoff, ivlen, iv);	else {		bcopy(sav->iv, iv, ivlen);		/* maybe it is better to overwrite dest, not source */		m_copyback(m, ivoff, ivlen, iv);	}	/* extend iv */	if (ivlen == blocklen)		;	else if (ivlen == 4 && blocklen == 8) {		bcopy(&iv[0], &iv[4], 4);		iv[4] ^= 0xff;		iv[5] ^= 0xff;		iv[6] ^= 0xff;		iv[7] ^= 0xff;	} else {		ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "		    "unsupported ivlen/blocklen: %d %d\n",		    algo->name, ivlen, blocklen));		m_freem(m);		return EINVAL;	}	if (m->m_pkthdr.len < bodyoff) {		ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n",		    algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));		m_freem(m);		return EINVAL;	}	if ((m->m_pkthdr.len - bodyoff) % blocklen) {		ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "		    "payload length must be multiple of %lu\n",		    algo->name, (unsigned long)algo->padbound));		m_freem(m);		return EINVAL;	}	s = m;	d = d0 = dp = NULL;	soff = doff = sn = dn = 0;	ivp = sp = NULL;	/* skip bodyoff */	while (soff < bodyoff) {		if (soff + s->m_len > bodyoff) {			sn = bodyoff - soff;			break;		}		soff += s->m_len;		s = s->m_next;	}	scut = s;	scutoff = sn;	/* skip over empty mbuf */	while (s && s->m_len == 0)		s = s->m_next;	while (soff < m->m_pkthdr.len) {		/* source */		if (sn + blocklen <= s->m_len) {			/* body is continuous */			sp = mtod(s, u_int8_t *) + sn;		} else {			/* body is non-continuous */			m_copydata(s, sn, blocklen, sbuf);			sp = sbuf;		}		/* destination */		if (!d || dn + blocklen > d->m_len) {			if (d)				dp = d;			MGET(d, M_DONTWAIT, MT_DATA);			i = m->m_pkthdr.len - (soff + sn);			if (d && i > MLEN) {				MCLGET(d, M_DONTWAIT);				if ((d->m_flags & M_EXT) == 0) {					m_free(d);					d = NULL;				}			}			if (!d) {				m_freem(m);				if (d0)					m_freem(d0);				return ENOBUFS;			}			if (!d0)				d0 = d;			if (dp)				dp->m_next = d;			d->m_len = 0;			d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;			if (d->m_len > i)				d->m_len = i;			dn = 0;		}		/* xor */		p = ivp ? ivp : iv;		q = sp;		for (i = 0; i < blocklen; i++)			q[i] ^= p[i];		/* encrypt */		(*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);		/* next iv */		ivp = mtod(d, u_int8_t *) + dn;		sn += blocklen;		dn += blocklen;		/* find the next source block */		while (s && sn >= s->m_len) {			sn -= s->m_len;			soff += s->m_len;			s = s->m_next;		}		/* skip over empty mbuf */		while (s && s->m_len == 0)			s = s->m_next;	}	m_freem(scut->m_next);	scut->m_len = scutoff;	scut->m_next = d0;	/* just in case */	bzero(iv, sizeof(iv));	bzero(sbuf, sizeof(sbuf));	key_sa_stir_iv(sav);	return 0;}/*------------------------------------------------------------*//* does not free m0 on error */intesp_auth(m0, skip, length, sav, sum)	struct mbuf *m0;	size_t skip;	/* offset to ESP header */	size_t length;	/* payload length */	struct secasvar *sav;	u_char *sum;{	struct mbuf *m;	size_t off;	struct ah_algorithm_state s;	u_char sumbuf[AH_MAXSUMSIZE];	const struct ah_algorithm *algo;	size_t siz;	int error;	/* sanity checks */	if (m0->m_pkthdr.len < skip) {		ipseclog((LOG_DEBUG, "esp_auth: mbuf length < skip\n"));		return EINVAL;	}	if (m0->m_pkthdr.len < skip + length) {		ipseclog((LOG_DEBUG,		    "esp_auth: mbuf length < skip + length\n"));		return EINVAL;	}	/*	 * length of esp part (excluding authentication data) must be 4n,	 * since nexthdr must be at offset 4n+3.	 */	if (length % 4) {		ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n"));		return EINVAL;	}	if (!sav) {		ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));		return EINVAL;	}	algo = ah_algorithm_lookup(sav->alg_auth);	if (!algo) {		ipseclog((LOG_ERR,		    "esp_auth: bad ESP auth algorithm passed: %d\n",		    sav->alg_auth));		return EINVAL;	}	m = m0;	off = 0;	siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1));	if (sizeof(sumbuf) < siz) {		ipseclog((LOG_DEBUG,		    "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n",		    (u_long)siz));		return EINVAL;	}	/* skip the header */	while (skip) {		if (!m)			panic("mbuf chain?");		if (m->m_len <= skip) {			skip -= m->m_len;			m = m->m_next;			off = 0;		} else {			off = skip;			skip = 0;		}	}	error = (*algo->init)(&s, sav);	if (error)		return error;	while (0 < length) {		if (!m)			panic("mbuf chain?");		if (m->m_len - off < length) {			(*algo->update)(&s, mtod(m, u_char *) + off,				m->m_len - off);			length -= m->m_len - off;			m = m->m_next;			off = 0;		} else {			(*algo->update)(&s, mtod(m, u_char *) + off, length);			break;		}	}	(*algo->result)(&s, sumbuf);	bcopy(sumbuf, sum, siz);	/* XXX */		return 0;}

⌨️ 快捷键说明

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