diff options
Diffstat (limited to 'programs/pluto/crypto.c')
-rw-r--r-- | programs/pluto/crypto.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/programs/pluto/crypto.c b/programs/pluto/crypto.c new file mode 100644 index 000000000..24939bd04 --- /dev/null +++ b/programs/pluto/crypto.c @@ -0,0 +1,261 @@ +/* crypto interfaces + * Copyright (C) 1998-2001 D. Hugh Redelmeier. + * + * 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. + * + * RCSID $Id: crypto.c,v 1.5 2005/12/06 22:51:34 as Exp $ + */ + +#include <stdio.h> +#include <string.h> +#include <stddef.h> +#include <sys/types.h> + +#include <freeswan.h> +#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */ +#include <crypto/des.h> + +#include <errno.h> + +#include "constants.h" +#include "defs.h" +#include "state.h" +#include "log.h" +#include "md5.h" +#include "sha1.h" +#include "crypto.h" /* requires sha1.h and md5.h */ +#include "alg_info.h" +#include "ike_alg.h" + + +/* moduli and generator. */ + +static MP_INT + modp1024_modulus, + modp1536_modulus, + modp2048_modulus, + modp3072_modulus, + modp4096_modulus, + modp6144_modulus, + modp8192_modulus; + +MP_INT groupgenerator; /* MODP group generator (2) */ + +static void do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc); + +static struct encrypt_desc crypto_encryptor_3des = +{ + algo_type: IKE_ALG_ENCRYPT, + algo_id: OAKLEY_3DES_CBC, + algo_next: NULL, + enc_ctxsize: sizeof(des_key_schedule) * 3, + enc_blocksize: DES_CBC_BLOCK_SIZE, + keydeflen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE, + keyminlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE, + keymaxlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE, + do_crypt: do_3des, +}; + +static struct hash_desc crypto_hasher_md5 = +{ + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_MD5, + algo_next: NULL, + hash_ctx_size: sizeof(MD5_CTX), + hash_digest_size: MD5_DIGEST_SIZE, + hash_init: (void (*)(void *)) MD5Init, + hash_update: (void (*)(void *, const u_int8_t *, size_t)) MD5Update, + hash_final: (void (*)(u_char *, void *)) MD5Final, +}; + +static struct hash_desc crypto_hasher_sha1 = +{ + algo_type: IKE_ALG_HASH, + algo_id: OAKLEY_SHA, + algo_next: NULL, + hash_ctx_size: sizeof(SHA1_CTX), + hash_digest_size: SHA1_DIGEST_SIZE, + hash_init: (void (*)(void *)) SHA1Init, + hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update, + hash_final: (void (*)(u_char *, void *)) SHA1Final, +}; + +void +init_crypto(void) +{ + if (mpz_init_set_str(&groupgenerator, MODP_GENERATOR, 10) != 0 + || mpz_init_set_str(&modp1024_modulus, MODP1024_MODULUS, 16) != 0 + || mpz_init_set_str(&modp1536_modulus, MODP1536_MODULUS, 16) != 0 + || mpz_init_set_str(&modp2048_modulus, MODP2048_MODULUS, 16) != 0 + || mpz_init_set_str(&modp3072_modulus, MODP3072_MODULUS, 16) != 0 + || mpz_init_set_str(&modp4096_modulus, MODP4096_MODULUS, 16) != 0 + || mpz_init_set_str(&modp6144_modulus, MODP6144_MODULUS, 16) != 0 + || mpz_init_set_str(&modp8192_modulus, MODP8192_MODULUS, 16) != 0) + exit_log("mpz_init_set_str() failed in init_crypto()"); + + ike_alg_add((struct ike_alg *) &crypto_encryptor_3des); + ike_alg_add((struct ike_alg *) &crypto_hasher_sha1); + ike_alg_add((struct ike_alg *) &crypto_hasher_md5); + ike_alg_init(); +} + +/* Oakley group description + * + * See RFC2409 "The Internet key exchange (IKE)" 6. + */ + +const struct oakley_group_desc unset_group = {0, NULL, 0}; /* magic signifier */ + +const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE] = { +# define BYTES(bits) (((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE) + { OAKLEY_GROUP_MODP1024, &modp1024_modulus, BYTES(1024) }, + { OAKLEY_GROUP_MODP1536, &modp1536_modulus, BYTES(1536) }, + { OAKLEY_GROUP_MODP2048, &modp2048_modulus, BYTES(2048) }, + { OAKLEY_GROUP_MODP3072, &modp3072_modulus, BYTES(3072) }, + { OAKLEY_GROUP_MODP4096, &modp4096_modulus, BYTES(4096) }, + { OAKLEY_GROUP_MODP6144, &modp6144_modulus, BYTES(6144) }, + { OAKLEY_GROUP_MODP8192, &modp8192_modulus, BYTES(8192) }, +# undef BYTES +}; + +const struct oakley_group_desc * +lookup_group(u_int16_t group) +{ + int i; + + for (i = 0; i != elemsof(oakley_group); i++) + if (group == oakley_group[i].group) + return &oakley_group[i]; + return NULL; +} + +/* Encryption Routines + * + * Each uses and updates the state object's st_new_iv. + * This must already be initialized. + */ + +/* encrypt or decrypt part of an IKE message using DES + * See RFC 2409 "IKE" Appendix B + */ +static void __attribute__ ((unused)) +do_des(bool enc, void *buf, size_t buf_len, struct state *st) +{ + des_key_schedule ks; + + (void) des_set_key((des_cblock *)st->st_enc_key.ptr, ks); + + passert(st->st_new_iv_len >= DES_CBC_BLOCK_SIZE); + st->st_new_iv_len = DES_CBC_BLOCK_SIZE; /* truncate */ + + des_ncbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len, + ks, + (des_cblock *)st->st_new_iv, enc); +} + +/* encrypt or decrypt part of an IKE message using 3DES + * See RFC 2409 "IKE" Appendix B + */ +static void +do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc) +{ + des_key_schedule ks[3]; + + passert (!key_size || (key_size==(DES_CBC_BLOCK_SIZE * 3))) + (void) des_set_key((des_cblock *)key + 0, ks[0]); + (void) des_set_key((des_cblock *)key + 1, ks[1]); + (void) des_set_key((des_cblock *)key + 2, ks[2]); + + des_ede3_cbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len, + ks[0], ks[1], ks[2], + (des_cblock *)iv, enc); +} + +/* hash and prf routines */ +void +crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st) +{ + passert(st->st_new_iv_len >= e->enc_blocksize); + st->st_new_iv_len = e->enc_blocksize; /* truncate */ + + e->do_crypt(buf, size, st->st_enc_key.ptr, st->st_enc_key.len, st->st_new_iv, enc); + /* + e->set_key(&ctx, st->st_enc_key.ptr, st->st_enc_key.len); + e->cbc_crypt(&ctx, buf, size, st->st_new_iv, enc); + */ +} + +/* HMAC package + * rfc2104.txt specifies how HMAC works. + */ + +void +hmac_init(struct hmac_ctx *ctx, + const struct hash_desc *h, + const u_char *key, size_t key_len) +{ + int k; + + ctx->h = h; + ctx->hmac_digest_size = h->hash_digest_size; + + /* Prepare the two pads for the HMAC */ + + memset(ctx->buf1, '\0', HMAC_BUFSIZE); + + if (key_len <= HMAC_BUFSIZE) + { + memcpy(ctx->buf1, key, key_len); + } + else + { + h->hash_init(&ctx->hash_ctx); + h->hash_update(&ctx->hash_ctx, key, key_len); + h->hash_final(ctx->buf1, &ctx->hash_ctx); + } + + memcpy(ctx->buf2, ctx->buf1, HMAC_BUFSIZE); + + for (k = 0; k < HMAC_BUFSIZE; k++) + { + ctx->buf1[k] ^= HMAC_IPAD; + ctx->buf2[k] ^= HMAC_OPAD; + } + + hmac_reinit(ctx); +} + +void +hmac_reinit(struct hmac_ctx *ctx) +{ + ctx->h->hash_init(&ctx->hash_ctx); + ctx->h->hash_update(&ctx->hash_ctx, ctx->buf1, HMAC_BUFSIZE); +} + +void +hmac_update(struct hmac_ctx *ctx, + const u_char *data, size_t data_len) +{ + ctx->h->hash_update(&ctx->hash_ctx, data, data_len); +} + +void +hmac_final(u_char *output, struct hmac_ctx *ctx) +{ + const struct hash_desc *h = ctx->h; + + h->hash_final(output, &ctx->hash_ctx); + + h->hash_init(&ctx->hash_ctx); + h->hash_update(&ctx->hash_ctx, ctx->buf2, HMAC_BUFSIZE); + h->hash_update(&ctx->hash_ctx, output, h->hash_digest_size); + h->hash_final(output, &ctx->hash_ctx); +} |