Пример #1
0
void
cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
{
	Cipher *c = cc->cipher;
	u_char *civ = NULL;
	int evplen;

	switch (c->number) {
	case SSH_CIPHER_SSH2:
	case SSH_CIPHER_DES:
	case SSH_CIPHER_BLOWFISH:
		evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
		if (evplen == 0)
			return;
		if (evplen != len)
			fatal("%s: wrong iv length %d != %d", __func__,
			    evplen, len);

#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
		if (c->evptype == evp_rijndael) {
			struct ssh_rijndael_ctx *aesc;

			aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
			if (aesc == NULL)
				fatal("%s: no rijndael context", __func__);
			civ = aesc->r_iv;
		} else
#endif
		if (c->evptype == evp_aes_128_ctr) {
			ssh_aes_ctr_iv(&cc->evp, 0, iv, len);
			return;
		} else {
			civ = cc->evp.iv;
		}
		break;
	case SSH_CIPHER_3DES: {
		struct ssh1_3des_ctx *desc;
		if (len != 24)
			fatal("%s: bad 3des iv length: %d", __func__, len);
		desc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
		if (desc == NULL)
			fatal("%s: no 3des context", __func__);
		debug3("%s: Copying 3DES IV", __func__);
		memcpy(iv, desc->k1.iv, 8);
		memcpy(iv + 8, desc->k2.iv, 8);
		memcpy(iv + 16, desc->k3.iv, 8);
		return;
	}
	default:
		fatal("%s: bad cipher %d", __func__, c->number);
	}
	memcpy(iv, civ, len);
}
Пример #2
0
void
cipher_set_keyiv(CipherContext *cc, u_char *iv)
{
	Cipher *c = cc->cipher;
	u_char *div = NULL;
	int evplen = 0;

	switch (c->number) {
	case SSH_CIPHER_SSH2:
	case SSH_CIPHER_DES:
	case SSH_CIPHER_BLOWFISH:
		evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
		if (evplen == 0)
			return;

#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
		if (c->evptype == evp_rijndael) {
			struct ssh_rijndael_ctx *aesc;

			aesc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
			if (aesc == NULL)
				fatal("%s: no rijndael context", __func__);
			div = aesc->r_iv;
		} else
#endif
		if (c->evptype == evp_aes_128_ctr) {
			ssh_aes_ctr_iv(&cc->evp, 1, iv, evplen);
			return;
		} else {
			div = cc->evp.iv;
		}
		break;
	case SSH_CIPHER_3DES: {
		struct ssh1_3des_ctx *desc;
		desc = EVP_CIPHER_CTX_get_app_data(&cc->evp);
		if (desc == NULL)
			fatal("%s: no 3des context", __func__);
		debug3("%s: Installed 3DES IV", __func__);
		memcpy(desc->k1.iv, iv, 8);
		memcpy(desc->k2.iv, iv + 8, 8);
		memcpy(desc->k3.iv, iv + 16, 8);
		return;
	}
	default:
		fatal("%s: bad cipher %d", __func__, c->number);
	}
	memcpy(div, iv, evplen);
}
Пример #3
0
static int
aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
		  const unsigned char *in,
		  unsigned int inl) /* encrypt/decrypt data */
{
    aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
    unsigned char b1[AES_BLOCK_SIZE];
    size_t i;

    if (inl != 16) /* libssh2 only ever encrypt one block */
	return 0;

/*
  To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each
  blocks of length L), the encryptor first encrypts <X> with <cipher>
  to obtain a block B1.  The block B1 is then XORed with P1 to generate
  the ciphertext block C1.  The counter X is then incremented
*/

    AES_encrypt(c->ctr, b1, &c->key);

    for (i = 0; i < 16; i++)
	*out++ = *in++ ^ b1[i];

    i = 15;
    while (c->ctr[i]++ == 0xFF) {
	if (i == 0)
	    break;
	i--;
    }

    return 1;
}
Пример #4
0
static int
aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
                  const unsigned char *in,
                  size_t inl) /* encrypt/decrypt data */
{
    aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
    unsigned char b1[AES_BLOCK_SIZE];
    int outlen = 0;

    if(inl != 16) /* libssh2 only ever encrypt one block */
        return 0;

    if(c == NULL) {
        return 0;
    }

/*
  To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each
  blocks of length L), the encryptor first encrypts <X> with <cipher>
  to obtain a block B1.  The block B1 is then XORed with P1 to generate
  the ciphertext block C1.  The counter X is then incremented
*/

    if(EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, c->ctr, AES_BLOCK_SIZE) != 1) {
        return 0;
    }

    _libssh2_xor_data(out, in, b1, AES_BLOCK_SIZE);
    _libssh2_aes_ctr_increment(c->ctr, AES_BLOCK_SIZE);

    return 1;
}
Пример #5
0
static int do_bf_ctr(EVP_CIPHER_CTX *ctx, unsigned char *dst,
    const unsigned char *src, size_t len) {
  struct bf_ctr_ex *bce;
  unsigned int n;
  unsigned char buf[BF_BLOCK];

  if (len == 0)
    return 1;

  bce = EVP_CIPHER_CTX_get_app_data(ctx);
  if (bce == NULL)
    return 0;

  n = 0;

  while ((len--) > 0) {
    pr_signals_handle();

    if (n == 0) {
      BF_LONG ctr[2];

      /* Ideally, we would not be using htonl/ntohl here, and the following
       * code would be as simple as:
       *
       *  memcpy(buf, bce->counter, BF_BLOCK);
       *  BF_encrypt((BF_LONG *) buf, &(bce->key));
       *
       * However, the above is susceptible to endianness issues.  The only
       * client that I could find which implements the blowfish-ctr cipher,
       * PuTTy, uses its own big-endian Blowfish implementation.  So the
       * above code will work with PuTTy, but only on big-endian machines.
       * For little-endian machines, we need to handle the endianness
       * ourselves.  Whee.
       */

      memcpy(&(ctr[0]), bce->counter, sizeof(BF_LONG));
      memcpy(&(ctr[1]), bce->counter + sizeof(BF_LONG), sizeof(BF_LONG));

      /* Convert to big-endian values before encrypting the counter... */
      ctr[0] = htonl(ctr[0]);
      ctr[1] = htonl(ctr[1]);

      BF_encrypt(ctr, &(bce->key));

      /* ...and convert back to little-endian before XOR'ing the counter in. */
      ctr[0] = ntohl(ctr[0]);
      ctr[1] = ntohl(ctr[1]);

      memcpy(buf, ctr, BF_BLOCK);

      ctr_incr(bce->counter, BF_BLOCK);
    }

    *(dst++) = *(src++) ^ buf[n];
    n = (n + 1) % BF_BLOCK;
  }

  return 1;
}
Пример #6
0
void
ssh_camellia_ctr_iv(EVP_CIPHER_CTX *evp, int doset, unsigned char * iv, unsigned int len)
{
	struct ssh_camellia_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) != NULL)
		if(doset)
			memcpy(c->camellia_counter, iv, len);
		else
			memcpy(iv, c->camellia_counter, len);
}
Пример #7
0
static int cleanup_bf_ctr(EVP_CIPHER_CTX *ctx) {
  struct bf_ctr_ex *bce;

  bce = EVP_CIPHER_CTX_get_app_data(ctx);
  if (bce != NULL) {
    pr_memscrub(bce, sizeof(struct bf_ctr_ex));
    free(bce);
    EVP_CIPHER_CTX_set_app_data(ctx, NULL);
  }

  return 1;
}
Пример #8
0
void
ssh_rijndael_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, u_int len)
{
	struct ssh_rijndael_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
		fatal("ssh_rijndael_iv: no context");
	if (doset)
		memcpy(c->r_iv, iv, len);
	else
		memcpy(iv, c->r_iv, len);
}
Пример #9
0
static int
ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
{
	struct ssh_aes_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
		bzero(c, sizeof(*c));
		free(c);
		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
	}
	return 1;
}
Пример #10
0
void
ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, size_t len)
{
	struct ssh_aes_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
		fatal("ssh_aes_ctr_iv: no context");
	if (doset)
		memcpy(c->aes_counter, iv, len);
	else
		memcpy(iv, c->aes_counter, len);
}
Пример #11
0
static int
ssh_rijndael_cleanup(EVP_CIPHER_CTX *ctx)
{
	struct ssh_rijndael_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
		memset(c, 0, sizeof(*c));
		free(c);
		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
	}
	return (1);
}
void
ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx)
{
	struct ssh_aes_ctr_ctx *c;
	int i;
	c = EVP_CIPHER_CTX_get_app_data(ctx);
	/* reconstruct threads */
	for (i = 0; i < CIPHER_THREADS; i++) {
		debug("spawned a thread");
		pthread_create(&c->tid[i], NULL, thread_loop, c);
	}
}
Пример #13
0
int
ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, size_t len)
{
	struct ssh_aes_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
		return SSH_ERR_INTERNAL_ERROR;
	if (doset)
		memcpy(c->aes_counter, iv, len);
	else
		memcpy(iv, c->aes_counter, len);
	return 0;
}
Пример #14
0
static int
ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len)
{
	struct ssh1_3des_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
		return 0;
	if (EVP_Cipher(&c->k1, dest, __UNCONST(src), len) == 0 ||
	    EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
	    EVP_Cipher(&c->k3, dest, dest, len) == 0)
		return 0;
	return 1;
}
/* this function is no longer used but might prove handy in the future
 * this comment also applies to ssh_aes_ctr_thread_reconstruction
 */
void
ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx)
{
	struct ssh_aes_ctr_ctx *c;
	int i;
	c = EVP_CIPHER_CTX_get_app_data(ctx);
	/* destroy threads */
	for (i = 0; i < CIPHER_THREADS; i++) {
		pthread_cancel(c->tid[i]);
	}
	for (i = 0; i < CIPHER_THREADS; i++) {
		pthread_join(c->tid[i], NULL);
	}
}
Пример #16
0
static int
ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
{
	struct ssh_aes_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
#ifdef __APPLE_CRYPTO__
		AES_destroy_ctx(&c->aes_ctx);
#endif
		memset(c, 0, sizeof(*c));
		xfree(c);
		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
	}
	return (1);
}
Пример #17
0
static int
ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len)
{
	struct ssh1_3des_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		error("ssh1_3des_cbc: no context");
		return (0);
	}
	if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
	    EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
	    EVP_Cipher(&c->k3, dest, dest, len) == 0)
		return (0);
	return (1);
}
Пример #18
0
static int
ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
{
	struct ssh1_3des_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
		EVP_CIPHER_CTX_cleanup(&c->k1);
		EVP_CIPHER_CTX_cleanup(&c->k2);
		EVP_CIPHER_CTX_cleanup(&c->k3);
		memset(c, 0, sizeof(*c));
		xfree(c);
		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
	}
	return (1);
}
Пример #19
0
static int
ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
{
	struct ssh1_3des_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
		EVP_CIPHER_CTX_cleanup(&c->k1);
		EVP_CIPHER_CTX_cleanup(&c->k2);
		EVP_CIPHER_CTX_cleanup(&c->k3);
		explicit_bzero(c, sizeof(*c));
		free(c);
		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
	}
	return 1;
}
Пример #20
0
static int
ssh_camellia_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc)
{
	struct ssh_camellia_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		c = malloc(sizeof(*c));
		EVP_CIPHER_CTX_set_app_data(ctx, c);
	}
	if (key != NULL)
		Camellia_set_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, &c->camellia_ctx);
	if (iv != NULL)
		memcpy(c->camellia_counter, iv, CAMELLIA_BLOCK_SIZE);
	return (1);
}
Пример #21
0
static int
aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
{
    aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);

    if (c == NULL) {
        return 1;
    }

    if (c->aes_ctx != NULL) {
        free(c->aes_ctx);
    }

    free(c);

    return 1;
}
Пример #22
0
static int
ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
    int enc)
{
	struct ssh_aes_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		c = xmalloc(sizeof(*c));
		EVP_CIPHER_CTX_set_app_data(ctx, c);
	}
	if (key != NULL)
		AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
		     &c->aes_ctx);
	if (iv != NULL)
		memcpy(c->aes_counter, iv, AES_BLOCK_SIZE);
	return (1);
}
Пример #23
0
static int
ssh_cast5_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc)
{
	struct ssh_cast5_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		c = malloc(sizeof(*c));
		EVP_CIPHER_CTX_set_app_data(ctx, c);
	}
	if (key != NULL) {
		CAST_set_key(&c->cast5_ctx, EVP_CIPHER_CTX_key_length(ctx), key);
	}

	if (iv != NULL)
		memcpy(c->cast5_counter, iv, CAST_BLOCK);
	return (1);
}
Пример #24
0
static int
ssh_rijndael_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
    LIBCRYPTO_EVP_INL_TYPE len)
{
	struct ssh_rijndael_ctx *c;
	u_char buf[RIJNDAEL_BLOCKSIZE];
	u_char *cprev, *cnow, *plain, *ivp;
	int i, j, blocks = len / RIJNDAEL_BLOCKSIZE;

	if (len == 0)
		return (1);
	if (len % RIJNDAEL_BLOCKSIZE)
		fatal("ssh_rijndael_cbc: bad len %d", len);
	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		error("ssh_rijndael_cbc: no context");
		return (0);
	}
	if (ctx->encrypt) {
		cnow  = dest;
		plain = (u_char *)src;
		cprev = c->r_iv;
		for (i = 0; i < blocks; i++, plain+=RIJNDAEL_BLOCKSIZE,
		    cnow+=RIJNDAEL_BLOCKSIZE) {
			for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
				buf[j] = plain[j] ^ cprev[j];
			rijndael_encrypt(&c->r_ctx, buf, cnow);
			cprev = cnow;
		}
		memcpy(c->r_iv, cprev, RIJNDAEL_BLOCKSIZE);
	} else {
		cnow  = (u_char *) (src+len-RIJNDAEL_BLOCKSIZE);
		plain = dest+len-RIJNDAEL_BLOCKSIZE;

		memcpy(buf, cnow, RIJNDAEL_BLOCKSIZE);
		for (i = blocks; i > 0; i--, cnow-=RIJNDAEL_BLOCKSIZE,
		    plain-=RIJNDAEL_BLOCKSIZE) {
			rijndael_decrypt(&c->r_ctx, cnow, plain);
			ivp = (i == 1) ? c->r_iv : cnow-RIJNDAEL_BLOCKSIZE;
			for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
				plain[j] ^= ivp[j];
		}
		memcpy(c->r_iv, buf, RIJNDAEL_BLOCKSIZE);
	}
	return (1);
}
Пример #25
0
static int
ssh_des3_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc)
{
	struct ssh_des3_ctr_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		c = malloc(sizeof(*c));
		EVP_CIPHER_CTX_set_app_data(ctx, c);
	}
	if (key != NULL) {
		DES_set_key((const_DES_cblock *)key, &c->des3_ctx[0]);
		DES_set_key((const_DES_cblock *)(key + 8), &c->des3_ctx[1]);
		DES_set_key((const_DES_cblock *)(key + 16), &c->des3_ctx[2]);
	}

	if (iv != NULL)
		memcpy(c->des3_counter, iv, DES_BLOCK_SIZE);
	return (1);
}
Пример #26
0
static int
ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
    int enc)
{
	struct ssh1_3des_ctx *c;
	u_char *k1, *k2, *k3;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		c = xcalloc(1, sizeof(*c));
		EVP_CIPHER_CTX_set_app_data(ctx, c);
	}
	if (key == NULL)
		return (1);
	if (enc == -1)
		enc = ctx->encrypt;
	k1 = k2 = k3 = (u_char *) key;
	k2 += 8;
	if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
		if (enc)
			k3 += 16;
		else
			k1 += 16;
	}
	EVP_CIPHER_CTX_init(&c->k1);
	EVP_CIPHER_CTX_init(&c->k2);
	EVP_CIPHER_CTX_init(&c->k3);
#ifdef SSH_OLD_EVP
	EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc);
	EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc);
	EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc);
#else
	if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
	    EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
	    EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
		memset(c, 0, sizeof(*c));
		free(c);
		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
		return (0);
	}
#endif
	return (1);
}
Пример #27
0
static int
ssh_rijndael_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
    int enc)
{
	struct ssh_rijndael_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		c = xmalloc(sizeof(*c));
		EVP_CIPHER_CTX_set_app_data(ctx, c);
	}
	if (key != NULL) {
		if (enc == -1)
			enc = ctx->encrypt;
		rijndael_set_key(&c->r_ctx, (u_char *)key,
		    8*EVP_CIPHER_CTX_key_length(ctx), enc);
	}
	if (iv != NULL)
		memcpy(c->r_iv, iv, RIJNDAEL_BLOCKSIZE);
	return (1);
}
Пример #28
0
int
ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
{
	struct ssh1_3des_ctx *c;

	if (len != 24)
		return SSH_ERR_INVALID_ARGUMENT;
	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
		return SSH_ERR_INTERNAL_ERROR;
	if (doset) {
		memcpy(c->k1.iv, iv, 8);
		memcpy(c->k2.iv, iv + 8, 8);
		memcpy(c->k3.iv, iv + 16, 8);
	} else {
		memcpy(iv, c->k1.iv, 8);
		memcpy(iv + 8, c->k2.iv, 8);
		memcpy(iv + 16, c->k3.iv, 8);
	}
	return 0;
}
Пример #29
0
static int
ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
{
	struct ssh1_3des_ctx *c;

	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
		error("ssh1_3des_cbc: no context");
		return (0);
	}
#ifdef SSH_OLD_EVP
	EVP_Cipher(&c->k1, dest, (u_char *)src, len);
	EVP_Cipher(&c->k2, dest, dest, len);
	EVP_Cipher(&c->k3, dest, dest, len);
#else
	if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
	    EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
	    EVP_Cipher(&c->k3, dest, dest, len) == 0)
		return (0);
#endif
	return (1);
}
Пример #30
0
void
ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
{
	struct ssh1_3des_ctx *c;

	if (len != 24)
		fatal("%s: bad 3des iv length: %d", __func__, len);
	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
		fatal("%s: no 3des context", __func__);
	if (doset) {
		debug3("%s: Installed 3DES IV", __func__);
		memcpy(c->k1.iv, iv, 8);
		memcpy(c->k2.iv, iv + 8, 8);
		memcpy(c->k3.iv, iv + 16, 8);
	} else {
		debug3("%s: Copying 3DES IV", __func__);
		memcpy(iv, c->k1.iv, 8);
		memcpy(iv + 8, c->k2.iv, 8);
		memcpy(iv + 16, c->k3.iv, 8);
	}
}