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

📄 crypto.c

📁 一个开源的VPN原码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  OpenVPN -- An application to securely tunnel IP networks *             over a single UDP port, with support for TLS-based *             session authentication and key exchange, *             packet encryption, packet authentication, and *             packet compression. * *  Copyright (C) 2002 James Yonan <jim@yonan.net> * *  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 (see the file COPYING included with this *  distribution); if not, write to the Free Software Foundation, Inc., *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "config.h"#ifdef USE_CRYPTO#include "syshead.h"#include "crypto.h"#include "error.h"#include "misc.h"#include "memdbg.h"/* * Check for key size creepage. */#if MAX_CIPHER_KEY_LENGTH < EVP_MAX_KEY_LENGTH#warning Some OpenSSL EVP ciphers now support key lengths greater than MAX_CIPHER_KEY_LENGTH -- consider increasing MAX_CIPHER_KEY_LENGTH#endif#if MAX_HMAC_KEY_LENGTH < EVP_MAX_MD_SIZE#warning Some OpenSSL HMAC message digests now support key lengths greater than MAX_HMAC_KEY_LENGTH -- consider increasing MAX_HMAC_KEY_LENGTH#endif/* * Encryption and Compression Routines. * * On entry, buf contains the input data and length. * On exit, it should be set to the output data and length. * * If buf->len is <= 0 we should return * If buf->len is set to 0 on exit it tells the caller to ignore the packet. * * work is a workspace buffer we are given of size BUF_SIZE. * work may be used to return output data, or the input buffer * may be modified and returned as output.  If output data is * returned in work, the data should start after EXTRA_FRAME bytes * of padding to leave room for downstream routines to prepend. * * Up to a total of EXTRA_FRAME bytes may be prepended to the input buf * by all routines (encryption, decryption, compression, and decompression). * * Note that the buf_prepend return will assert if we try to * make a header bigger than EXTRA_FRAME.  This should not * happen unless the frame parameters are wrong. * * If opt->iv is not NULL it will be used and the residual * IV will be returned. * */#define CRYPT_ERROR(format) \  do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false)#define CRYPT_ERROR_ARGS(format, args...) \  do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix, args); goto error_exit; } while (false)voidopenvpn_encrypt (struct buffer *buf, struct buffer work,		 const struct crypto_options *opt,		 const struct frame* frame,		 const time_t current){  if (buf->len > 0 && opt->key_ctx_bi)    {      struct key_ctx *ctx = &opt->key_ctx_bi->encrypt;      /* Do Encrypt from buf -> work */      if (ctx->cipher)	{	  uint8_t *iv = opt->iv;	  uint8_t *residual_iv;	  const int iv_size = EVP_CIPHER_CTX_iv_length (ctx->cipher);	  const unsigned int mode = EVP_CIPHER_CTX_mode (ctx->cipher);  	  int outlen;	  /* Put packet ID in plaintext buffer or IV, depending on cipher mode */	  if (mode == EVP_CIPH_CBC_MODE)	    {	      if (opt->packet_id)		{		  struct packet_id_net pin;		  packet_id_alloc_outgoing (&opt->packet_id->send, &pin, opt->packet_id_long_form);		  ASSERT (packet_id_write (&pin, buf, opt->packet_id_long_form, true));		}	    }	  else if (mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE)	    {	      struct packet_id_net pin;	      struct buffer b;	      ASSERT (iv);             /* IV and packet-ID required */	      ASSERT (opt->packet_id); /*  for this mode. */	      packet_id_alloc_outgoing (&opt->packet_id->send, &pin, true);	      memset (iv, 0, iv_size);	      buf_set_write (&b, iv, iv_size);	      ASSERT (packet_id_write (&pin, &b, true, false));	    }	  else /* We only support CBC, CFB, or OFB modes right now */	    {	      ASSERT (0);	    }	  /* initialize work buffer with EXTRA_FRAME bytes of prepend capacity */	  ASSERT (buf_init (&work, EXTRA_FRAME (frame)));	  /* show the IV's initial state */	  if (iv)	    msg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv, iv_size, 0));	  msg (D_PACKET_CONTENT, "ENCRYPT FROM: %s",	       format_hex (BPTR (buf), BLEN (buf), 80));	  /* cipher_ctx was already initialized with key & keylen */	  ASSERT (EVP_CipherInit_ov (ctx->cipher, NULL, NULL, iv, DO_ENCRYPT));	  /* Buffer overflow check (should never happen) */	  ASSERT (buf_safe (&work, buf->len + EVP_CIPHER_CTX_block_size (ctx->cipher)));	  /* Encrypt packet ID, payload */	  ASSERT (EVP_CipherUpdate_ov (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf)));	  work.len += outlen;	  /* Flush the encryption buffer */	  ASSERT (EVP_CipherFinal (ctx->cipher, (residual_iv = BPTR (&work) + outlen), &outlen));	  work.len += outlen;	  ASSERT (outlen == iv_size);	  /* prepend the IV to the ciphertext */	  if (iv)	    {	      uint8_t *output = buf_prepend (&work, iv_size);	      ASSERT (output);	      memcpy (output, iv, iv_size);	      /* save the residual IV */	      memcpy (iv, residual_iv, iv_size);	    }	  msg (D_PACKET_CONTENT, "ENCRYPT TO: %s",	       format_hex (BPTR (&work), BLEN (&work), 80));	}      else				/* No Encryption */	{	  if (opt->packet_id)	    {	      struct packet_id_net pin;	      packet_id_alloc_outgoing (&opt->packet_id->send, &pin, opt->packet_id_long_form);	      ASSERT (packet_id_write (&pin, buf, opt->packet_id_long_form, true));	    }	  work = *buf;	}      /* HMAC the ciphertext (or plaintext if !cipher) */      if (ctx->hmac)	{	  int hmac_len;	  uint8_t *output;	  HMAC_Init (ctx->hmac, NULL, 0, NULL);	  HMAC_Update (ctx->hmac, BPTR (&work), BLEN (&work));	  output = buf_prepend (&work, HMAC_size (ctx->hmac));	  ASSERT (output);	  HMAC_Final (ctx->hmac, output, &hmac_len);	  ASSERT (hmac_len == HMAC_size (ctx->hmac));	}      *buf = work;    }  return;}/* * If opt->iv is not NULL, we will read an IV from the packet. * opt->iv is not modified. */voidopenvpn_decrypt (struct buffer *buf, struct buffer work,		 const struct crypto_options *opt,		 const struct frame* frame,		 const time_t current){  static const char error_prefix[] = "Authenticate/Decrypt packet error";  if (buf->len > 0 && opt->key_ctx_bi)    {      struct key_ctx *ctx = &opt->key_ctx_bi->decrypt;      struct packet_id_net pin;      bool have_pin = false;      /* Verify the HMAC */      if (ctx->hmac)	{	  int hmac_len;	  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */	  int in_hmac_len;	  HMAC_Init (ctx->hmac, NULL, 0, NULL);	  /* Assume the length of the input HMAC */	  hmac_len = HMAC_size (ctx->hmac);	  /* Authentication fails if insufficient data in packet for HMAC */	  if (buf->len < hmac_len)	    CRYPT_ERROR ("missing authentication info");	  HMAC_Update (ctx->hmac, BPTR (buf) + hmac_len,		       BLEN (buf) - hmac_len);	  HMAC_Final (ctx->hmac, local_hmac, &in_hmac_len);	  ASSERT (hmac_len == in_hmac_len);	  /* Compare locally computed HMAC with packet HMAC */	  if (memcmp (local_hmac, BPTR (buf), hmac_len))	    CRYPT_ERROR ("packet HMAC authentication failed");	  ASSERT (buf_advance (buf, hmac_len));	}      /* Decrypt packet ID + payload */      if (ctx->cipher)	{	  const unsigned int mode = EVP_CIPHER_CTX_mode (ctx->cipher);	  const int iv_size = EVP_CIPHER_CTX_iv_length (ctx->cipher);	  uint8_t iv[EVP_MAX_IV_LENGTH];	  int outlen;	  /* initialize work buffer with EXTRA_FRAME bytes of prepend capacity */	  ASSERT (buf_init (&work, EXTRA_FRAME (frame)));	  /* use IV if user requested it */	  CLEAR (iv);	  if (opt->iv)	    {	      if (buf->len < iv_size)		CRYPT_ERROR ("missing IV info");	      memcpy (iv, BPTR (buf), iv_size);	      ASSERT (buf_advance (buf, iv_size));	    }	  /* show the IV's initial state */	  if (iv)	    msg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv, iv_size, 0));	  if (buf->len < 1)	    CRYPT_ERROR ("missing payload");	  /* ctx->cipher was already initialized with key & keylen */	  if (!EVP_CipherInit_ov (ctx->cipher, NULL, NULL, iv, DO_DECRYPT))	    CRYPT_ERROR ("cipher init failed");	  /* Buffer overflow check (should never happen) */	  if (!buf_safe (&work, buf->len))	    CRYPT_ERROR ("buffer overflow");	  /* Decrypt packet ID, payload */	  if (!EVP_CipherUpdate_ov (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf)))	    CRYPT_ERROR ("cipher update failed");	  work.len += outlen;	  /* Flush the decryption buffer */	  if (!EVP_CipherFinal (ctx->cipher, BPTR (&work) + outlen, &outlen))	    CRYPT_ERROR ("cipher final failed");	  work.len += outlen;	  msg (D_PACKET_CONTENT, "DECRYPT TO: %s",	       format_hex (BPTR (&work), BLEN (&work), 80));	  /* Get packet ID from plaintext buffer or IV, depending on cipher mode */	  {	    if (mode == EVP_CIPH_CBC_MODE)	      {		if (opt->packet_id)		  {		    if (!packet_id_read (&pin, &work, opt->packet_id_long_form))		      CRYPT_ERROR ("error reading CBC packet-id");		    have_pin = true;		  }	      }	    else if (mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE)	      {		struct buffer b;		ASSERT (iv);             /* IV and packet-ID required */		ASSERT (opt->packet_id); /*  for this mode. */		buf_set_read (&b, iv, iv_size);		if (!packet_id_read (&pin, &b, true))		  CRYPT_ERROR ("error reading CFB/OFB packet-id");		have_pin = true;	      }	    else /* We only support CBC, CFB, or OFB modes right now */	      {		ASSERT (0);	      }	  }	}      else	{	  work = *buf;	  if (opt->packet_id)	    {	      if (!packet_id_read (&pin, &work, opt->packet_id_long_form))		CRYPT_ERROR ("error reading packet-id");	      have_pin = true;	    }	}            if (have_pin)	{	  if (packet_id_test (&opt->packet_id->rec, &pin))	    packet_id_add (&opt->packet_id->rec, &pin);	  else	    CRYPT_ERROR_ARGS ("bad packet ID (may be a replay): %s", packet_id_net_print (&pin));	}      *buf = work;    }  return; error_exit:  buf->len = 0;  return;}/* * How many bytes will we add to frame buffer for a given * set of crypto options? */voidcrypto_adjust_frame_parameters(struct frame *frame,			       const struct key_type* kt,			       bool cipher_defined,			       bool iv,			       bool packet_id,			       bool packet_id_long_form){  frame->extra_frame +=    (packet_id ? packet_id_size (packet_id_long_form) : 0) +    ((cipher_defined && iv) ? EVP_CIPHER_iv_length (kt->cipher) : 0) +    (cipher_defined ? EVP_CIPHER_block_size(kt->cipher) : 0) + /* worst case padding expansion */    kt->hmac_length;}static const EVP_CIPHER *get_cipher (const char *ciphername){  const EVP_CIPHER *cipher = NULL;  ASSERT (ciphername);  cipher = EVP_get_cipherbyname (ciphername);  if ( !(cipher && cipher_ok (OBJ_nid2sn (EVP_CIPHER_nid (cipher)))))

⌨️ 快捷键说明

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