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

📄 crypto.c

📁 OpenVPN is a robust and highly flexible tunneling application that uses all of the encryption, authe
💻 C
📖 第 1 页 / 共 3 页
字号:
      if (warn)	msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used");    }}const char *kt_cipher_name (const struct key_type *kt){  if (kt->cipher)    return EVP_CIPHER_name (kt->cipher);  else    return "[null-cipher]";}const char *kt_digest_name (const struct key_type *kt){  if (kt->digest)    return EVP_MD_name (kt->digest);  else    return "[null-digest]";}intkt_key_size (const struct key_type *kt){  if (kt->cipher_length)    return kt->cipher_length * 8;  else if (kt->cipher)    return EVP_CIPHER_key_length (kt->cipher) * 8;  else    return 0;}/* given a key and key_type, build a key_ctx */voidinit_key_ctx (struct key_ctx *ctx, struct key *key,	      const struct key_type *kt, int enc,	      const char *prefix){  CLEAR (*ctx);  if (kt->cipher && kt->cipher_length > 0)    {      ALLOC_OBJ (ctx->cipher, EVP_CIPHER_CTX);      init_cipher (ctx->cipher, kt->cipher, key, kt, enc, prefix);    }  if (kt->digest && kt->hmac_length > 0)    {      ALLOC_OBJ (ctx->hmac, HMAC_CTX);      init_hmac (ctx->hmac, kt->digest, key, kt, prefix);    }}voidfree_key_ctx (struct key_ctx *ctx){  if (ctx->cipher)    {      EVP_CIPHER_CTX_cleanup (ctx->cipher);      free (ctx->cipher);      ctx->cipher = NULL;    }  if (ctx->hmac)    {      HMAC_CTX_cleanup (ctx->hmac);      free (ctx->hmac);      ctx->hmac = NULL;    }}voidfree_key_ctx_bi (struct key_ctx_bi *ctx){  free_key_ctx(&ctx->encrypt);  free_key_ctx(&ctx->decrypt);}/* * Return number of DES cblocks for the current * key type or 0 if not a DES cipher. */static intn_DES_cblocks (const struct key_type *kt){  int ret = 0;  const char *name = OBJ_nid2sn (EVP_CIPHER_nid (kt->cipher));  if (name)    {      if (!strncmp (name, "DES-", 4))	{	  ret = EVP_CIPHER_key_length (kt->cipher) / sizeof (DES_cblock);	}      else if (!strncmp (name, "DESX-", 5))	{	  ret = 1;	}    }  msg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);  return ret;}static boolcheck_key_DES (struct key *key, const struct key_type *kt, int ndc){  int i;  struct buffer b;  buf_set_read (&b, key->cipher, kt->cipher_length);  for (i = 0; i < ndc; ++i)    {      DES_cblock *dc = (DES_cblock*) buf_read_alloc (&b, sizeof (DES_cblock));      if (!dc)	{	  msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material");	  return false;	}      if (DES_is_weak_key(dc))	{	  msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected");	  return false;	}      if (!DES_check_key_parity (dc))	{	  msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected");	  return false;	}    }  return true;}static voidfixup_key_DES (struct key *key, const struct key_type *kt, int ndc){  int i;  struct buffer b;  buf_set_read (&b, key->cipher, kt->cipher_length);  for (i = 0; i < ndc; ++i)    {      DES_cblock *dc = (DES_cblock*) buf_read_alloc(&b, sizeof(DES_cblock));      if (!dc)	{	  msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material");	  return;	}      DES_set_odd_parity (dc);    }}static boolkey_is_zero (struct key *key, const struct key_type *kt){  int i;  for (i = 0; i < kt->cipher_length; ++i)    if (key->cipher[i])      return false;  msg (D_CRYPT_ERRORS, "CRYPTO INFO: WARNING: zero key detected");  return true;}/* * Make sure that cipher key is a valid key for current key_type. */boolcheck_key (struct key *key, const struct key_type *kt){  if (kt->cipher)    {      /*       * Check for zero key       */      if (key_is_zero(key, kt))	return false;      /*       * Check for weak or semi-weak DES keys.       */      {	const int ndc = n_DES_cblocks (kt);	if (ndc)	  return check_key_DES (key, kt, ndc);	else	  return true;      }    }  return true;}/* * Make safe mutations to key to ensure it is valid, * such as ensuring correct parity on DES keys. * * This routine cannot guarantee it will generate a good * key.  You must always call check_key after this routine * to make sure. */ voidfixup_key (struct key *key, const struct key_type *kt){  struct gc_arena gc = gc_new ();  if (kt->cipher)    {      const struct key orig = *key;      const int ndc = n_DES_cblocks (kt);      if (ndc)	fixup_key_DES (key, kt, ndc);      if (check_debug_level (D_CRYPTO_DEBUG))	{	  if (memcmp (orig.cipher, key->cipher, kt->cipher_length))	    msg (D_CRYPTO_DEBUG, "CRYPTO INFO: fixup_key: before=%s after=%s",		 format_hex (orig.cipher, kt->cipher_length, 0, &gc),		 format_hex (key->cipher, kt->cipher_length, 0, &gc));	}    }  gc_free (&gc);}voidcheck_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use_iv){  if (cfb_ofb_mode (kt) && !(packet_id && use_iv))    msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher");}boolcfb_ofb_mode (const struct key_type* kt){  if (kt->cipher) {    const unsigned int mode = EVP_CIPHER_mode (kt->cipher);    return mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE;  } else    return false;}/* * Generate a random key.  If key_type is provided, make * sure generated key is valid for key_type. */voidgenerate_key_random (struct key *key, const struct key_type *kt){  int cipher_len = MAX_CIPHER_KEY_LENGTH;  int hmac_len = MAX_HMAC_KEY_LENGTH;  struct gc_arena gc = gc_new ();  do {    CLEAR (*key);    if (kt)      {	if (kt->cipher && kt->cipher_length > 0 && kt->cipher_length <= cipher_len)	  cipher_len = kt->cipher_length;	if (kt->digest && kt->hmac_length > 0 && kt->hmac_length <= hmac_len)	  hmac_len = kt->hmac_length;      }    if (!RAND_bytes (key->cipher, cipher_len)	|| !RAND_bytes (key->hmac, hmac_len))      msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation");    msg (D_SHOW_KEY_SOURCE, "Cipher source entropy: %s", format_hex (key->cipher, cipher_len, 0, &gc));    msg (D_SHOW_KEY_SOURCE, "HMAC source entropy: %s", format_hex (key->hmac, hmac_len, 0, &gc));    if (kt)      fixup_key (key, kt);  } while (kt && !check_key (key, kt));  gc_free (&gc);}/* * Print key material */voidkey2_print (const struct key2* k,	    const struct key_type *kt,	    const char* prefix0,	    const char* prefix1){  struct gc_arena gc = gc_new ();  ASSERT (k->n == 2);  msg (D_SHOW_KEY_SOURCE, "%s (cipher): %s",       prefix0,       format_hex (k->keys[0].cipher, kt->cipher_length, 0, &gc));  msg (D_SHOW_KEY_SOURCE, "%s (hmac): %s",       prefix0,       format_hex (k->keys[0].hmac, kt->hmac_length, 0, &gc));  msg (D_SHOW_KEY_SOURCE, "%s (cipher): %s",       prefix1,       format_hex (k->keys[1].cipher, kt->cipher_length, 0, &gc));  msg (D_SHOW_KEY_SOURCE, "%s (hmac): %s",       prefix1,       format_hex (k->keys[1].hmac, kt->hmac_length, 0, &gc));  gc_free (&gc);}voidtest_crypto (const struct crypto_options *co, struct frame* frame){  int i, j;  struct gc_arena gc = gc_new ();  struct buffer src = alloc_buf_gc (TUN_MTU_SIZE (frame), &gc);  struct buffer work = alloc_buf_gc (BUF_SIZE (frame), &gc);  struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);  struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);  struct buffer buf = clear_buf();  /* init work */  ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));  msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode.");  for (i = 1; i <= TUN_MTU_SIZE (frame); ++i)    {      update_time ();      msg (M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i);      /*       * Load src with random data.       */      ASSERT (buf_init (&src, 0));      ASSERT (i <= src.capacity);      src.len = i;      ASSERT (RAND_pseudo_bytes (BPTR (&src), BLEN (&src)));      /* copy source to input buf */      buf = work;      memcpy (buf_write_alloc (&buf, BLEN (&src)), BPTR (&src), BLEN (&src));      /* encrypt */      openvpn_encrypt (&buf, encrypt_workspace, co, frame);      /* decrypt */      openvpn_decrypt (&buf, decrypt_workspace, co, frame);      /* compare */      if (buf.len != src.len)	msg (M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len);      for (j = 0; j < i; ++j)	{	  const uint8_t in = *(BPTR (&src) + j);	  const uint8_t out = *(BPTR (&buf) + j);	  if (in != out)	    msg (M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out);	}    }  msg (M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED.");  gc_free (&gc);}#ifdef USE_SSLvoidget_tls_handshake_key (const struct key_type *key_type,		       struct key_ctx_bi *ctx,		       const char *passphrase_file,		       bool key_direction){  if (passphrase_file && key_type->hmac_length)    {      struct key2 key2;      struct key_type kt = *key_type;      struct key_direction_state kds;      /* for control channel we are only authenticating, not encrypting */      kt.cipher_length = 0;      kt.cipher = NULL;      /* first try to parse as an OpenVPN static key file */      read_key_file (&key2, passphrase_file, false);      /* succeeded? */      if (key2.n == 2)	{	  msg (M_INFO,	       "Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file",	       passphrase_file);	}      else	{	  int hash_size;	  CLEAR (key2);	  /* failed, now try to get hash from a freeform file */	  hash_size = read_passphrase_hash (passphrase_file,					    kt.digest,					    key2.keys[0].hmac,					    MAX_HMAC_KEY_LENGTH);	  ASSERT (hash_size == kt.hmac_length);	  /* suceeded */	  key2.n = 1;	  msg (M_INFO,	       "Control Channel Authentication: using '%s' as a free-form passphrase file",	       passphrase_file);	}      /* handle key direction */      key_direction_state_init (&kds, key_direction);      must_have_n_keys (passphrase_file, "tls-auth", &key2, kds.need_keys);      /* initialize hmac key in both directions */      init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], &kt, DO_ENCRYPT,		    "Outgoing Control Channel Authentication");      init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], &kt, DO_DECRYPT,		    "Incoming Control Channel Authentication");      CLEAR (key2);    }  else    {      CLEAR (*ctx);    }}#endif/* header and footer for static key file */static const char static_key_head[] = "-----BEGIN " PACKAGE_NAME " Static key V1-----";static const char static_key_foot[] = "-----END " PACKAGE_NAME " Static key V1-----";static const char printable_char_fmt[] =  "Non-Hex character ('%c') found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";static const char unprintable_char_fmt[] =  "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";/* read key from file */voidread_key_file (struct key2 *key2, const char *filename, bool must_succeed){  struct gc_arena gc = gc_new ();  struct buffer in = alloc_buf_gc (64, &gc);  int fd, size;  uint8_t hex_byte[3] = {0, 0, 0};  /* parse info */  int hb_index = 0;  int line_num = 1;  int line_index = 0;  int match = 0;  /* output */  uint8_t* out = (uint8_t*) &key2->keys;  const int keylen = sizeof (key2->keys);  int count = 0;  /* parse states */# define PARSE_INITIAL        0# define PARSE_HEAD           1# define PARSE_DATA           2# define PARSE_DATA_COMPLETE  3# define PARSE_FOOT           4# define PARSE_FINISHED       5  int state = PARSE_INITIAL;  /* constants */  const int hlen = strlen (static_key_head);  const int flen = strlen (static_key_foot);  const int onekeylen = sizeof (key2->keys[0]);  CLEAR (*key2);  fd = open (filename, O_RDONLY);  if (fd == -1)    msg (M_ERR, "Cannot open file key file '%s'", filename);  while ((size = read (fd, in.data, in.capacity)))    {      const char *cp = (char *)in.data;      while (size)	{	  const char c = *cp;#if 0	  msg (M_INFO, "char='%c' s=%d ln=%d li=%d m=%d c=%d",	       c, state, line_num, line_index, match, count);#endif	  if (c == '\n')	    {	      line_index = match = 0;	      ++line_num;	      	    }	  else	    {	      /* first char of new line */	      if (!line_index)		{		  /* first char of line after header line? */		  if (state == PARSE_HEAD)		    state = PARSE_DATA;		  /* first char of footer */		  if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-')		    state = PARSE_FOOT;		}	      /* compare read chars with header line */	      if (state == PARSE_INITIAL)		{		  if (line_index < hlen && c == static_key_head[line_index])		    {		      if (++match == hlen)			state = PARSE_HEAD;		    }		}	      /* compare read chars with footer line */	      if (state == PARSE_FOOT)		{		  if (line_index < flen && c == static_key_foot[line_index])		    {		      if (++match == flen)

⌨️ 快捷键说明

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