📄 crypto.c
字号:
msg (M_SSLERR, "Cipher algorithm '%s' not found", ciphername); return cipher;}static const EVP_MD *get_md (const char *digest){ const EVP_MD *md = NULL; ASSERT (digest); md = EVP_get_digestbyname (digest); if (!md) msg (M_SSLERR, "Message digest algorithm '%s' not found", digest); return md;}static voidinit_cipher (EVP_CIPHER_CTX * ctx, const EVP_CIPHER * cipher, struct key *key, const struct key_type *kt, int enc, const char *prefix){ EVP_CIPHER_CTX_init (ctx); if (!EVP_CipherInit_ov (ctx, cipher, NULL, NULL, enc)) msg (M_SSLERR, "EVP cipher init #1");#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH if (!EVP_CIPHER_CTX_set_key_length (ctx, kt->cipher_length)) msg (M_SSLERR, "EVP set key size");#endif if (!EVP_CipherInit_ov (ctx, NULL, key->cipher, NULL, enc)) msg (M_SSLERR, "EVP cipher init #2"); msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key", prefix, OBJ_nid2sn (EVP_CIPHER_CTX_nid (ctx)), EVP_CIPHER_CTX_key_length (ctx) * 8); /* make sure we used a big enough key */ ASSERT (EVP_CIPHER_CTX_key_length (ctx) <= kt->cipher_length); msg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, format_hex (key->cipher, kt->cipher_length, 0)); msg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", prefix, EVP_CIPHER_CTX_block_size (ctx), EVP_CIPHER_CTX_iv_length (ctx));}static voidinit_hmac (HMAC_CTX * ctx, const EVP_MD * digest, struct key *key, const struct key_type *kt, const char *prefix){ HMAC_Init (ctx, key->hmac, kt->hmac_length, digest); msg (D_HANDSHAKE, "%s: Using %d bit message digest '%s' for HMAC authentication", prefix, HMAC_size (ctx) * 8, OBJ_nid2sn (EVP_MD_type (digest))); /* make sure we used a big enough key */ ASSERT (HMAC_size (ctx) <= kt->hmac_length); msg (D_SHOW_KEYS, "%s: HMAC KEY: %s", prefix, format_hex (key->hmac, kt->hmac_length, 0)); msg (D_CRYPTO_DEBUG, "%s: HMAC size=%d block_size=%d", prefix, EVP_MD_size (digest), EVP_MD_block_size (digest));}/* build a key_type */voidinit_key_type (struct key_type *kt, const char *ciphername, bool ciphername_defined, const char *authname, bool authname_defined, int keysize, bool cfb_ofb_allowed){ CLEAR (*kt); if (ciphername && ciphername_defined) { kt->cipher = get_cipher (ciphername); kt->cipher_length = EVP_CIPHER_key_length (kt->cipher); if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH) kt->cipher_length = keysize; /* check legal cipher mode */ { const unsigned int mode = EVP_CIPHER_mode (kt->cipher); if (!(mode == EVP_CIPH_CBC_MODE || (cfb_ofb_allowed && (mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE)))) msg (M_FATAL, "Cipher %s uses a mode not supported by OpenVPN in your current configuration. CBC mode is always supported, while CFB and OFB modes are supported only when using SSL/TLS authentication and key exchange mode.", ciphername); } } else { msg (M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used"); } if (authname && authname_defined) { kt->digest = get_md (authname); kt->hmac_length = EVP_MD_size (kt->digest); } else { msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used"); }}/* 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) { ASSERT (ctx->cipher = (EVP_CIPHER_CTX *) malloc (sizeof (EVP_CIPHER_CTX))); init_cipher (ctx->cipher, kt->cipher, key, kt, enc, prefix); } if (kt->digest && kt->hmac_length > 0) { ASSERT (ctx->hmac = (HMAC_CTX *) malloc (sizeof (HMAC_CTX))); init_hmac (ctx->hmac, kt->digest, key, kt, prefix); }}void free_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; }}void free_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){ 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), format_hex (key->cipher, kt->cipher_length, 0)); } }}voidcheck_replay_iv_consistency(const struct key_type *kt, bool packet_id, bool iv){ if (cfb_ofb_mode (kt) && !(packet_id && 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; 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; } ASSERT (RAND_bytes (key->cipher, cipher_len)); ASSERT (RAND_bytes (key->hmac, hmac_len)); if (kt) fixup_key (key, kt); } while (kt && !check_key (key, kt));}voidrandomize_iv (uint8_t *iv){ if (RAND_bytes (iv, EVP_MAX_IV_LENGTH) < 0) msg (M_SSLERR, "RAND_bytes failed");}voidtest_crypto (const struct crypto_options *co, struct frame* frame){ int i, j; struct buffer src = alloc_buf_gc (MTU_SIZE (frame)); struct buffer work = alloc_buf_gc (BUF_SIZE (frame)); struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame)); struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame)); struct buffer buf = clear_buf(); /* init work */ ASSERT (buf_init (&work, EXTRA_FRAME (frame))); msg (M_INFO, "Entering OpenVPN crypto self-test mode."); for (i = 1; i <= MTU_SIZE (frame); ++i) { const time_t current = time (NULL); uint8_t iv_save[EVP_MAX_IV_LENGTH]; 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)); /* save IV */ memcpy (iv_save, co->iv, EVP_MAX_IV_LENGTH); /* encrypt */ openvpn_encrypt (&buf, encrypt_workspace, co, frame, current);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -