static void stub_compress(struct buffer *buf, struct buffer work, struct compress_context *compctx, const struct frame *frame) { if (buf->len <= 0) { return; } if (compctx->flags & COMP_F_SWAP) { uint8_t *head = BPTR(buf); uint8_t *tail = BEND(buf); ASSERT(buf_safe(buf, 1)); ++buf->len; /* move head byte of payload to tail */ *tail = *head; *head = NO_COMPRESS_BYTE_SWAP; } else { uint8_t *header = buf_prepend(buf, 1); *header = NO_COMPRESS_BYTE; } }
static void lz4v2_compress(struct buffer *buf, struct buffer work, struct compress_context *compctx, const struct frame *frame) { bool compressed; if (buf->len <= 0) { return; } compressed = do_lz4_compress(buf, &work, compctx, frame); /* On Error just return */ if (buf->len == 0) { return; } /* did compression save us anything? Include 2 byte compression header * in calculation */ if (compressed && work.len + 2 < buf->len) { ASSERT(buf_prepend(&work, 2)); uint8_t *head = BPTR(&work); head[0] = COMP_ALGV2_INDICATOR_BYTE; head[1] = COMP_ALGV2_LZ4_BYTE; *buf = work; } else { compv2_escape_data_ifneeded(buf); } }
/* In the v2 compression schemes, an uncompressed packet has * has no opcode in front, unless the first byte is 0x50. In this * case the packet needs to be escaped */ void compv2_escape_data_ifneeded (struct buffer *buf) { uint8_t *head = BPTR (buf); if (head[0] != COMP_ALGV2_INDICATOR_BYTE) return; /* Header is 0x50 */ ASSERT(buf_prepend(buf, 2)); head = BPTR (buf); head[0] = COMP_ALGV2_INDICATOR_BYTE; head[1] = COMP_ALGV2_UNCOMPRESSED; }
/* * Return a buffer for write that is a subset of another buffer */ struct buffer buf_sub (struct buffer *buf, int size, bool prepend) { struct buffer ret; uint8_t *data; CLEAR (ret); data = prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size); if (data) { ret.capacity = size; ret.data = data; } return ret; }
static void lzo_compress(struct buffer *buf, struct buffer work, struct compress_context *compctx, const struct frame *frame) { lzo_uint zlen = 0; int err; bool compressed = false; if (buf->len <= 0) { return; } /* * In order to attempt compression, length must be at least COMPRESS_THRESHOLD, * and our adaptive level must give the OK. */ if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled(compctx)) { const size_t ps = PAYLOAD_SIZE(frame); ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); ASSERT(buf_safe(&work, ps + COMP_EXTRA_BUFFER(ps))); if (buf->len > ps) { dmsg(D_COMP_ERRORS, "LZO compression buffer overflow"); buf->len = 0; return; } err = LZO_COMPRESS(BPTR(buf), BLEN(buf), BPTR(&work), &zlen, compctx->wu.lzo.wmem); if (err != LZO_E_OK) { dmsg(D_COMP_ERRORS, "LZO compression error: %d", err); buf->len = 0; return; } ASSERT(buf_safe(&work, zlen)); work.len = zlen; compressed = true; dmsg(D_COMP, "LZO compress %d -> %d", buf->len, work.len); compctx->pre_compress += buf->len; compctx->post_compress += work.len; /* tell adaptive level about our success or lack thereof in getting any size reduction */ if (compctx->flags & COMP_F_ADAPTIVE) { lzo_adaptive_compress_data(&compctx->wu.lzo.ac, buf->len, work.len); } } /* did compression save us anything ? */ if (compressed && work.len < buf->len) { uint8_t *header = buf_prepend(&work, 1); *header = LZO_COMPRESS_BYTE; *buf = work; } else { uint8_t *header = buf_prepend(buf, 1); *header = NO_COMPRESS_BYTE; } }
void openvpn_encrypt (struct buffer *buf, struct buffer work, const struct crypto_options *opt, const struct frame* frame) { struct gc_arena gc; gc_init (&gc); 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_buf[OPENVPN_MAX_IV_LENGTH]; const int iv_size = cipher_ctx_iv_length (ctx->cipher); const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); int outlen; if (cipher_kt_mode_cbc(cipher_kt)) { CLEAR (iv_buf); /* generate pseudo-random IV */ if (opt->flags & CO_USE_IV) prng_bytes (iv_buf, iv_size); /* Put packet ID in plaintext buffer or IV, depending on cipher mode */ if (opt->packet_id) { struct packet_id_net pin; packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } } else if (cipher_kt_mode_ofb_cfb(cipher_kt)) { struct packet_id_net pin; struct buffer b; ASSERT (opt->flags & CO_USE_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_buf, 0, iv_size); buf_set_write (&b, iv_buf, 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 FRAME_HEADROOM bytes of prepend capacity */ ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); /* set the IV pseudo-randomly */ if (opt->flags & CO_USE_IV) dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); /* cipher_ctx was already initialized with key & keylen */ ASSERT (cipher_ctx_reset(ctx->cipher, iv_buf)); /* Buffer overflow check */ if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) { msg (D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d", buf->capacity, buf->offset, buf->len, work.capacity, work.offset, work.len, cipher_ctx_block_size (ctx->cipher)); goto err; } /* Encrypt packet ID, payload */ ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))); ASSERT (buf_inc_len(&work, outlen)); /* Flush the encryption buffer */ ASSERT (cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen)); ASSERT (buf_inc_len(&work, outlen)); /* For all CBC mode ciphers, check the last block is complete */ ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC || outlen == iv_size); /* prepend the IV to the ciphertext */ if (opt->flags & CO_USE_IV) { uint8_t *output = buf_prepend (&work, iv_size); ASSERT (output); memcpy (output, iv_buf, iv_size); } dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (&work), BLEN (&work), 80, &gc)); } else /* No Encryption */ { if (opt->packet_id) { struct packet_id_net pin; packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } work = *buf; } /* HMAC the ciphertext (or plaintext if !cipher) */ if (ctx->hmac) { uint8_t *output = NULL; hmac_ctx_reset (ctx->hmac); hmac_ctx_update (ctx->hmac, BPTR(&work), BLEN(&work)); output = buf_prepend (&work, hmac_ctx_size(ctx->hmac)); ASSERT (output); hmac_ctx_final (ctx->hmac, output); } *buf = work; } gc_free (&gc); return; err: crypto_clear_error(); buf->len = 0; gc_free (&gc); return; }