crypt_dh.c

来自「ipsec vpn」· C语言 代码 · 共 539 行 · 第 1/2 页

C
539
字号
/*  * Cryptographic helper function - calculate KE and nonce * Copyright (C) 2004 Michael C. Richardson <mcr@xelerance.com> * * 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.  See <http://www.fsf.org/copyleft/gpl.txt>. * * 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. * * This code was developed with the support of IXIA communications. * * RCSID $Id: crypt_dh.c,v 1.8.2.1 2006/03/20 13:32:03 paul Exp $ */#include <stdlib.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <sys/queue.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/types.h>#include <signal.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "defs.h"#include "packet.h"#include "demux.h"#include "crypto.h"#include "rnd.h"#include "state.h"#include "pluto_crypt.h"#include "oswlog.h"#include "log.h"#include "timer.h"#include "ike_alg.h"#include "secrets.h"/** Compute DH shared secret from our local secret and the peer's public value. * We make the leap that the length should be that of the group * (see quoted passage at start of ACCEPT_KE). */static voidcalc_dh_shared(chunk_t *shared, const chunk_t g	       , const MP_INT *sec	       , const struct oakley_group_desc *group){    MP_INT mp_g, mp_shared;    struct timeval tv0, tv1;    unsigned long tv_diff;    gettimeofday(&tv0, NULL);    n_to_mpz(&mp_g, g.ptr, g.len);    mpz_init(&mp_shared);    mpz_powm(&mp_shared, &mp_g, sec, group->modulus);    mpz_clear(&mp_g);    *shared = mpz_to_n(&mp_shared, group->bytes);    mpz_clear(&mp_shared);    gettimeofday(&tv1, NULL);    tv_diff=(tv1.tv_sec  - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec);    DBG(DBG_CRYPT,     	DBG_log("calc_dh_shared(): time elapsed (%s): %ld usec"		, enum_show(&oakley_group_names, group->group)		, tv_diff);       );    /* if took more than 200 msec ... */    if (tv_diff > 200000) {	loglog(RC_LOG_SERIOUS, "WARNING: calc_dh_shared(): for %s took "			"%ld usec"		, enum_show(&oakley_group_names, group->group)		, tv_diff);    }    DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", *shared);}/* SKEYID for preshared keys. * See draft-ietf-ipsec-ike-01.txt 4.1 */static voidskeyid_preshared(const chunk_t pss		 , const chunk_t ni		 , const chunk_t nr		 , const struct hash_desc *hasher		 , chunk_t *skeyid){    struct hmac_ctx ctx;    passert(hasher != NULL);    DBG(DBG_CRYPT,	DBG_log("Skey inputs (PSK+NI+NR)");	DBG_dump_chunk("ni: ", ni);	DBG_dump_chunk("nr: ", nr));        hmac_init_chunk(&ctx, hasher, pss);    hmac_update_chunk(&ctx, ni);    hmac_update_chunk(&ctx, nr);    hmac_final_chunk(*skeyid, "st_skeyid in skeyid_preshared()", &ctx);    DBG(DBG_CRYPT,	DBG_dump_chunk("keyid: ", *skeyid));}static voidskeyid_digisig(const chunk_t ni	       , const chunk_t nr	       , const chunk_t shared	       , const struct hash_desc *hasher	       , chunk_t *skeyid){    struct hmac_ctx ctx;    chunk_t nir;    DBG(DBG_CRYPT,	DBG_log("skeyid inputs (digi+NI+NR+shared) hasher: %s", hasher->common.name);	DBG_dump_chunk("shared: ", shared);	DBG_dump_chunk("ni: ", ni);	DBG_dump_chunk("nr: ", nr));        /* We need to hmac_init with the concatenation of Ni_b and Nr_b,     * so we have to build a temporary concatentation.     */    nir.len = ni.len + nr.len;    nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_digisig");    memcpy(nir.ptr, ni.ptr, ni.len);    memcpy(nir.ptr+ ni.len, nr.ptr, nr.len);    hmac_init_chunk(&ctx, hasher, nir);    pfree(nir.ptr);    hmac_update_chunk(&ctx, shared);    hmac_final_chunk(*skeyid, "st_skeyid in skeyid_digisig()", &ctx);    DBG(DBG_CRYPT,	DBG_dump_chunk("keyid: ", *skeyid));}/* Generate the SKEYID_* and new IV * See draft-ietf-ipsec-ike-01.txt 4.1 */static voidcalc_skeyids_iv(struct pcr_skeyid_q *skq		, chunk_t shared		, const size_t keysize     /* = st->st_oakley.enckeylen/BITS_PER_BYTE; */		, chunk_t *skeyid          /* output */		, chunk_t *skeyid_d        /* output */		, chunk_t *skeyid_a        /* output */		, chunk_t *skeyid_e        /* output */		, chunk_t *new_iv		, chunk_t *enc_key    ){    oakley_auth_t auth = skq->auth;    oakley_hash_t hash = skq->hash;    const struct hash_desc *hasher = crypto_get_hasher(hash);    chunk_t pss;      chunk_t ni;    chunk_t nr;    chunk_t gi;    chunk_t gr;    chunk_t icookie;    chunk_t rcookie;    /* this doesn't take any memory */    setchunk_fromwire(gi, &skq->gi, skq);    setchunk_fromwire(gr, &skq->gr, skq);    setchunk_fromwire(ni, &skq->ni, skq);    setchunk_fromwire(nr, &skq->nr, skq);    setchunk_fromwire(icookie, &skq->icookie, skq);    setchunk_fromwire(rcookie, &skq->rcookie, skq);    /* Generate the SKEYID */    switch (auth)    {	case OAKLEY_PRESHARED_KEY:	    setchunk_fromwire(pss,    &skq->pss, skq);	    skeyid_preshared(pss, ni, nr, hasher, skeyid);	    break;	case OAKLEY_RSA_SIG:	    skeyid_digisig(ni, nr, shared, hasher, skeyid);	    break;	case OAKLEY_DSS_SIG:	    /* XXX */	case OAKLEY_RSA_ENC:	case OAKLEY_RSA_ENC_REV:	case OAKLEY_ELGAMAL_ENC:	case OAKLEY_ELGAMAL_ENC_REV:	    /* XXX */	default:	    bad_case(auth);    }    /* generate SKEYID_* from SKEYID */    {	struct hmac_ctx ctx;	/* SKEYID_D */	hmac_init_chunk(&ctx, hasher, *skeyid);	hmac_update_chunk(&ctx, shared);	hmac_update_chunk(&ctx, icookie);	hmac_update_chunk(&ctx, rcookie);	hmac_update(&ctx, "\0", 1);	hmac_final_chunk(*skeyid_d, "st_skeyid_d in generate_skeyids_iv()", &ctx);	/* SKEYID_A */	hmac_reinit(&ctx);	hmac_update_chunk(&ctx, *skeyid_d);	hmac_update_chunk(&ctx, shared);	hmac_update_chunk(&ctx, icookie);	hmac_update_chunk(&ctx, rcookie);	hmac_update(&ctx, "\1", 1);	hmac_final_chunk(*skeyid_a, "st_skeyid_a in generate_skeyids_iv()", &ctx);	/* SKEYID_E */	hmac_reinit(&ctx);	hmac_update_chunk(&ctx, *skeyid_a);	hmac_update_chunk(&ctx, shared);	hmac_update_chunk(&ctx, icookie);	hmac_update_chunk(&ctx, rcookie);	hmac_update(&ctx, "\2", 1);	hmac_final_chunk(*skeyid_e, "st_skeyid_e in generate_skeyids_iv()", &ctx);    }    /* generate IV */    {	union hash_ctx hash_ctx;	new_iv->len = hasher->hash_digest_len;	new_iv->ptr = alloc_bytes(new_iv->len, "calculated new iv");        DBG(DBG_CRYPT,            DBG_dump_chunk("DH_i:", gi);            DBG_dump_chunk("DH_r:", gr);        );	hasher->hash_init(&hash_ctx);	hasher->hash_update(&hash_ctx, gi.ptr, gi.len);	hasher->hash_update(&hash_ctx, gr.ptr, gr.len);	hasher->hash_final(new_iv->ptr, &hash_ctx);    }    /* Oakley Keying Material     * Derived from Skeyid_e: if it is not big enough, generate more     * using the PRF.     * See RFC 2409 "IKE" Appendix B     */    {	u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN];	u_char *k = skeyid_e->ptr;	if (keysize > skeyid_e->len)	{	    struct hmac_ctx ctx;	    size_t i = 0;

⌨️ 快捷键说明

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