Пример #1
0
/* Derive the 33 subkeys from KEY and store them in SUBKEYS.  */
static void
serpent_subkeys_generate (serpent_key_t key, serpent_subkeys_t subkeys)
{
  u32 w[8];		/* The `prekey'.  */
  u32 ws[4];
  u32 wt[4];

  /* Initialize with key values.  */
  w[0] = key[0];
  w[1] = key[1];
  w[2] = key[2];
  w[3] = key[3];
  w[4] = key[4];
  w[5] = key[5];
  w[6] = key[6];
  w[7] = key[7];

  /* Expand to intermediate key using the affine recurrence.  */
#define EXPAND_KEY4(wo, r)                                                     \
  wo[0] = w[(r+0)%8] =                                                         \
    rol (w[(r+0)%8] ^ w[(r+3)%8] ^ w[(r+5)%8] ^ w[(r+7)%8] ^ PHI ^ (r+0), 11); \
  wo[1] = w[(r+1)%8] =                                                         \
    rol (w[(r+1)%8] ^ w[(r+4)%8] ^ w[(r+6)%8] ^ w[(r+0)%8] ^ PHI ^ (r+1), 11); \
  wo[2] = w[(r+2)%8] =                                                         \
    rol (w[(r+2)%8] ^ w[(r+5)%8] ^ w[(r+7)%8] ^ w[(r+1)%8] ^ PHI ^ (r+2), 11); \
  wo[3] = w[(r+3)%8] =                                                         \
    rol (w[(r+3)%8] ^ w[(r+6)%8] ^ w[(r+0)%8] ^ w[(r+2)%8] ^ PHI ^ (r+3), 11);

#define EXPAND_KEY(r)       \
  EXPAND_KEY4(ws, (r));     \
  EXPAND_KEY4(wt, (r + 4));

  /* Calculate subkeys via S-Boxes, in bitslice mode.  */
  EXPAND_KEY (0); SBOX (3, ws, subkeys[0]); SBOX (2, wt, subkeys[1]);
  EXPAND_KEY (8); SBOX (1, ws, subkeys[2]); SBOX (0, wt, subkeys[3]);
  EXPAND_KEY (16); SBOX (7, ws, subkeys[4]); SBOX (6, wt, subkeys[5]);
  EXPAND_KEY (24); SBOX (5, ws, subkeys[6]); SBOX (4, wt, subkeys[7]);
  EXPAND_KEY (32); SBOX (3, ws, subkeys[8]); SBOX (2, wt, subkeys[9]);
  EXPAND_KEY (40); SBOX (1, ws, subkeys[10]); SBOX (0, wt, subkeys[11]);
  EXPAND_KEY (48); SBOX (7, ws, subkeys[12]); SBOX (6, wt, subkeys[13]);
  EXPAND_KEY (56); SBOX (5, ws, subkeys[14]); SBOX (4, wt, subkeys[15]);
  EXPAND_KEY (64); SBOX (3, ws, subkeys[16]); SBOX (2, wt, subkeys[17]);
  EXPAND_KEY (72); SBOX (1, ws, subkeys[18]); SBOX (0, wt, subkeys[19]);
  EXPAND_KEY (80); SBOX (7, ws, subkeys[20]); SBOX (6, wt, subkeys[21]);
  EXPAND_KEY (88); SBOX (5, ws, subkeys[22]); SBOX (4, wt, subkeys[23]);
  EXPAND_KEY (96); SBOX (3, ws, subkeys[24]); SBOX (2, wt, subkeys[25]);
  EXPAND_KEY (104); SBOX (1, ws, subkeys[26]); SBOX (0, wt, subkeys[27]);
  EXPAND_KEY (112); SBOX (7, ws, subkeys[28]); SBOX (6, wt, subkeys[29]);
  EXPAND_KEY (120); SBOX (5, ws, subkeys[30]); SBOX (4, wt, subkeys[31]);
  EXPAND_KEY4 (ws, 128); SBOX (3, ws, subkeys[32]);

  wipememory (ws, sizeof (ws));
  wipememory (wt, sizeof (wt));
  wipememory (w, sizeof (w));
}
Пример #2
0
static void
fpm_rotate(gchar* field, gint len)
{
  /* After we use addnoise (above) we ensure blocks don't look identical
   * unless all 8 chars in the block are part of the password.  This
   * routine makes us use all three blocks equally rather than fill the
   * first, then the second, etc.   This makes it so none of the blocks
   * in the password will remain constant from save to save, even if the
   * password is from 7-20 characters long.  Note that passwords from
   * 21-24 characters start to fill blocks, and so will be constant.
   */

  gint num_blocks;
  gchar* tmp;
  gint b, i;

  g_assert(blocksize>0);
  num_blocks = len/blocksize;

  g_assert(len==num_blocks*blocksize);
  tmp=g_malloc0(len+1);
  for(b=0;b<num_blocks;b++)
  {
    for(i=0;i<blocksize;i++) tmp[b*blocksize+i] = field[i*num_blocks+b];
  }
  memcpy(field, tmp, len);
  wipememory(tmp, len);
  g_free(tmp);
}
static void
encode_seskey( DEK *dek, DEK **seskey, byte *enckey )
{
    CIPHER_HANDLE hd;
    byte buf[33];

    assert ( dek->keylen <= 32 );
    if(!*seskey)
      {
	*seskey=xmalloc_clear(sizeof(DEK));
	(*seskey)->keylen=dek->keylen;
	(*seskey)->algo=dek->algo;
	make_session_key(*seskey);
	/*log_hexdump( "thekey", c->key, c->keylen );*/
      }

    buf[0] = (*seskey)->algo;
    memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );
    
    hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
    cipher_setkey( hd, dek->key, dek->keylen );
    cipher_setiv( hd, NULL, 0 );
    cipher_encrypt( hd, buf, buf, (*seskey)->keylen + 1 );
    cipher_close( hd );

    memcpy( enckey, buf, (*seskey)->keylen + 1 );
    wipememory( buf, sizeof buf ); /* burn key */
}
Пример #4
0
/* Initialize CONTEXT with the key KEY of KEY_LENGTH bits.  */
static void
serpent_setkey_internal (serpent_context_t *context,
			 const byte *key, unsigned int key_length)
{
  serpent_key_t key_prepared;

  serpent_key_prepare (key, key_length, key_prepared);
  serpent_subkeys_generate (key_prepared, context->keys);

#ifdef USE_AVX2
  context->use_avx2 = 0;
  if ((_gcry_get_hw_features () & HWF_INTEL_AVX2))
    {
      context->use_avx2 = 1;
    }
#endif

#ifdef USE_NEON
  context->use_neon = 0;
  if ((_gcry_get_hw_features () & HWF_ARM_NEON))
    {
      context->use_neon = 1;
    }
#endif

  wipememory (key_prepared, sizeof(key_prepared));
}
Пример #5
0
static int
do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
{
    int i, rc = 0;
    u32 n;
    byte buf[1000]; /* this buffer has the plaintext! */
    int nbytes;

    write_header(out, ctb, calc_plaintext( pt ) );
    iobuf_put(out, pt->mode );
    iobuf_put(out, pt->namelen );
    for(i=0; i < pt->namelen; i++ )
	iobuf_put(out, pt->name[i] );
    rc = write_32(out, pt->timestamp );
    if (rc) 
      return rc;

    n = 0;
    while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) {
      rc = iobuf_write (out, buf, nbytes);
      if (rc)
        break;
      n += nbytes;
    }
    wipememory(buf,1000); /* burn the buffer */
    if( (ctb&0x40) && !pt->len )
      iobuf_set_partial_block_mode(out, 0 ); /* turn off partial */
    if( pt->len && n != pt->len )
      log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
		(ulong)n, (ulong)pt->len );

    return rc;
}
Пример #6
0
static void
encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
{
  gcry_cipher_hd_t hd;
  byte buf[33];

  assert ( dek->keylen <= 32 );
  if (!*seskey)
    {
      *seskey=xmalloc_clear(sizeof(DEK));
      (*seskey)->keylen=dek->keylen;
      (*seskey)->algo=dek->algo;
      make_session_key(*seskey);
      /*log_hexdump( "thekey", c->key, c->keylen );*/
    }

  /* The encrypted session key is prefixed with a one-octet algorithm id.  */
  buf[0] = (*seskey)->algo;
  memcpy( buf + 1, (*seskey)->key, (*seskey)->keylen );

  /* We only pass already checked values to the following fucntion,
     thus we consider any failure as fatal.  */
  if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1))
    BUG ();
  if (gcry_cipher_setkey (hd, dek->key, dek->keylen))
    BUG ();
  gcry_cipher_setiv (hd, NULL, 0);
  gcry_cipher_encrypt (hd, buf, (*seskey)->keylen + 1, NULL, 0);
  gcry_cipher_close (hd);

  memcpy( enckey, buf, (*seskey)->keylen + 1 );
  wipememory( buf, sizeof buf ); /* burn key */
}
Пример #7
0
/* Read data from the system RNG if availavle.  */
static void
read_system_rng (void (*add)(const void*, size_t, enum random_origins),
                 enum random_origins requester)
{
  BYTE buffer[ SYSTEMRNG_BYTES + 8 ];
  int quality = 0;

  if (!system_rng_available)
    return;

  /* Read SYSTEMRNG_BYTES bytes from the system RNG.  We don't rely on
     this for all our randomness requirements (particularly the
     software RNG) in case it's broken in some way.  */
  if (hRNGProv)
    {
      if (pCryptGenRandom (hRNGProv, SYSTEMRNG_BYTES, buffer))
        quality = 80;
    }
  else if (pRtlGenRandom)
    {
      if ( pRtlGenRandom (buffer, SYSTEMRNG_BYTES))
        quality = 50;
    }
  if (quality > 0)
    {
      if (debug_me)
        log_debug ("rndw32#read_system_rng: got %d bytes of quality %d\n",
                   SYSTEMRNG_BYTES, quality);
      (*add) (buffer, SYSTEMRNG_BYTES, requester);
      wipememory (buffer, SYSTEMRNG_BYTES);
    }
}
Пример #8
0
/* Release all resources associated with the cipher handle H. H may be
   NULL in which case this is a no-operation. */
void
gcry_cipher_close (gcry_cipher_hd_t h)
{
  if (! h)
    return;

  if ((h->magic != CTX_MAGIC_SECURE)
      && (h->magic != CTX_MAGIC_NORMAL))
    _gcry_fatal_error(GPG_ERR_INTERNAL,
		      "gcry_cipher_close: already closed/invalid handle");
  else
    h->magic = 0;

  /* Release module.  */
  ath_mutex_lock (&ciphers_registered_lock);
  _gcry_module_release (h->module);
  ath_mutex_unlock (&ciphers_registered_lock);

  /* We always want to wipe out the memory even when the context has
     been allocated in secure memory.  The user might have disabled
     secure memory or is using his own implementation which does not
     do the wiping.  To accomplish this we need to keep track of the
     actual size of this structure because we have no way to known
     how large the allocated area was when using a standard malloc. */
  wipememory (h, h->actual_handle_size);

  gcry_free (h);
}
Пример #9
0
/* Release all resources associated with the cipher handle H. H may be
   NULL in which case this is a no-operation. */
void
_gcry_cipher_close (gcry_cipher_hd_t h)
{
  size_t off;

  if (!h)
    return;

  if ((h->magic != CTX_MAGIC_SECURE)
      && (h->magic != CTX_MAGIC_NORMAL))
    _gcry_fatal_error(GPG_ERR_INTERNAL,
		      "gcry_cipher_close: already closed/invalid handle");
  else
    h->magic = 0;

  /* We always want to wipe out the memory even when the context has
     been allocated in secure memory.  The user might have disabled
     secure memory or is using his own implementation which does not
     do the wiping.  To accomplish this we need to keep track of the
     actual size of this structure because we have no way to known
     how large the allocated area was when using a standard malloc. */
  off = h->handle_offset;
  wipememory (h, h->actual_handle_size);

  xfree ((char*)h - off);
}
Пример #10
0
/* Bulk decryption of complete blocks in CBC mode.  This function is only
   intended for the bulk encryption feature of cipher.c. */
void
_gcry_blowfish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
		       const void *inbuf_arg, size_t nblocks)
{
  BLOWFISH_context *ctx = context;
  unsigned char *outbuf = outbuf_arg;
  const unsigned char *inbuf = inbuf_arg;
  unsigned char savebuf[BLOWFISH_BLOCKSIZE];
  int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE;

#ifdef USE_AMD64_ASM
  {
    if (nblocks >= 4)
      burn_stack_depth += 5 * sizeof(void*);

    /* Process data in 4 block chunks. */
    while (nblocks >= 4)
      {
        _gcry_blowfish_amd64_cbc_dec(ctx, outbuf, inbuf, iv);

        nblocks -= 4;
        outbuf += 4 * BLOWFISH_BLOCKSIZE;
        inbuf  += 4 * BLOWFISH_BLOCKSIZE;
      }

    /* Use generic code to handle smaller chunks... */
  }
#elif defined(USE_ARM_ASM)
  {
    /* Process data in 2 block chunks. */
    while (nblocks >= 2)
      {
        _gcry_blowfish_arm_cbc_dec(ctx, outbuf, inbuf, iv);

        nblocks -= 2;
        outbuf += 2 * BLOWFISH_BLOCKSIZE;
        inbuf  += 2 * BLOWFISH_BLOCKSIZE;
      }

    /* Use generic code to handle smaller chunks... */
  }
#endif

  for ( ;nblocks; nblocks-- )
    {
      /* INBUF is needed later and it may be identical to OUTBUF, so store
         the intermediate result to SAVEBUF.  */
      do_decrypt_block (ctx, savebuf, inbuf);

      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE);
      inbuf += BLOWFISH_BLOCKSIZE;
      outbuf += BLOWFISH_BLOCKSIZE;
    }

  wipememory(savebuf, sizeof(savebuf));
  _gcry_burn_stack(burn_stack_depth);
}
Пример #11
0
void
_gcry_burn_stack (int bytes)
{
    char buf[64];
    
    wipememory (buf, sizeof buf);
    bytes -= sizeof buf;
    if (bytes > 0)
        _gcry_burn_stack (bytes);
}
static void
burn_stack (int bytes)
{
    char buf[128];

    wipememory(buf,sizeof buf);
    bytes -= sizeof buf;
    if (bytes > 0)
        burn_stack (bytes);
}
Пример #13
0
void fpm_crypt_set_password(gchar *password) {
    gchar *prehash = "";
    byte *hash;

    new_salt = get_new_salt(cipher->salt_len);
    hash = g_malloc(cipher->hash_len);

    if(cipher_algo == AES256) {
	fpm_pkcs5_pbkdf2((guchar *)password, strlen(password), new_salt, cipher->salt_len, hash, cipher->hash_len, PBKDF2_ITERATIONS);
    } else {
	prehash = g_strdup_printf("%s%s", new_salt, password);
	md5(prehash, hash);
    }

    fpm_setkey(new_context, hash, cipher->hash_len);

    if (cipher_algo == BLOWFISH)
	wipememory(prehash, strlen(prehash));

    wipememory(hash, cipher->hash_len);
    g_free(hash);
}
Пример #14
0
void fpm_crypt_init(gchar* password) {
  gchar *prehash1 = "", *prehash2 = "";
  byte *hash_1, *hash_2;

  old_context = g_malloc(cipher->contextsize);
  new_context = g_malloc(cipher->contextsize);

  hash_1 = g_malloc(cipher->hash_len);
  hash_2 = g_malloc(cipher->hash_len);

  if(cipher_algo == AES256) {
    fpm_pkcs5_pbkdf2((guchar *)password, strlen(password), old_salt, cipher->salt_len, hash_1, cipher->hash_len, PBKDF2_ITERATIONS);
    fpm_pkcs5_pbkdf2((guchar *)password, strlen(password), new_salt, cipher->salt_len, hash_2, cipher->hash_len, PBKDF2_ITERATIONS);
  } else {
    prehash1 = g_strdup_printf("%s%s", old_salt, password);
    prehash2 = g_strdup_printf("%s%s", new_salt, password);

    md5(prehash1, hash_1);
    md5(prehash2, hash_2);
  }

  fpm_setkey(old_context, hash_1, cipher->hash_len);
  fpm_setkey(new_context, hash_2, cipher->hash_len);

  wipememory(hash_1, cipher->hash_len);
  wipememory(hash_2, cipher->hash_len);

  g_free(hash_1);
  g_free(hash_2);

  if (cipher_algo == BLOWFISH) {
    wipememory(prehash1, strlen(prehash1));
    wipememory(prehash2, strlen(prehash2));
    g_free(prehash1);
    g_free(prehash2);
  }
}
Пример #15
0
void
_gcry_mpi_free_limb_space( mpi_ptr_t a, unsigned int nlimbs)
{
  if (a)
    {
      size_t len = nlimbs * sizeof(mpi_limb_t);

      /* If we have information on the number of allocated limbs, we
         better wipe that space out.  This is a failsafe feature if
         secure memory has been disabled or was not properly
         implemented in user provided allocation functions. */
      if (len)
        wipememory (a, len);
      xfree(a);
    }
}
Пример #16
0
static gcry_err_code_t
do_arcfour_setkey (void *context, const byte *key, unsigned int keylen)
{
  static int initialized;
  static const char* selftest_failed;
  int i, j;
  byte karr[256];
  ARCFOUR_context *ctx = (ARCFOUR_context *) context;

  if (!initialized )
    {
      initialized = 1;
      selftest_failed = selftest();
      if( selftest_failed )
        log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed );
    }
  if( selftest_failed )
    return GPG_ERR_SELFTEST_FAILED;

  if( keylen < 40/8 ) /* we want at least 40 bits */
    return GPG_ERR_INV_KEYLEN;

  ctx->idx_i = ctx->idx_j = 0;
  for (i=0; i < 256; i++ )
    ctx->sbox[i] = i;
  for (i=j=0; i < 256; i++,j++ )
    {
      if (j >= keylen)
        j = 0;
      karr[i] = key[j];
    }
  for (i=j=0; i < 256; i++ )
    {
      int t;
      j = (j + ctx->sbox[i] + karr[i]) & 255;
      t = ctx->sbox[i];
      ctx->sbox[i] = ctx->sbox[j];
      ctx->sbox[j] = t;
    }
  wipememory( karr, sizeof(karr) );

  return GPG_ERR_NO_ERROR;
}
Пример #17
0
/* Create a new session key and append it as a tuple to the memory
   buffer MB.

   The EncFS daemon takes a passphrase from stdin and internally
   mangles it by means of some KDF from OpenSSL.  We want to store a
   binary key but we need to make sure that certain characters are not
   used because the EncFS utility reads it from stdin and obviously
   acts on some of the characters.  This we replace CR (in case of an
   MSDOS version of EncFS), LF (the delimiter used by EncFS) and Nul
   (because it is unlikely to work).  We use 32 bytes (256 bit)
   because that is sufficient for the largest cipher (AES-256) and in
   addition gives enough margin for a possible entropy degradation by
   the KDF.  */
gpg_error_t
be_encfs_create_new_keys (membuf_t *mb)
{
  char *buffer;
  int i, j;

  /* Allocate a buffer of 32 bytes plus 8 spare bytes we may need to
     replace the unwanted values.  */
  buffer = xtrymalloc_secure (32+8);
  if (!buffer)
    return gpg_error_from_syserror ();

  /* Randomize the buffer.  STRONG random should be enough as it is a
     good compromise between security and performance.  The
     anticipated usage of this tool is the quite often creation of new
     containers and thus this should not deplete the system's entropy
     tool too much.  */
  gcry_randomize (buffer, 32+8, GCRY_STRONG_RANDOM);
  for (i=j=0; i < 32; i++)
    {
      if (buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == 0 )
        {
          /* Replace.  */
          if (j == 8)
            {
              /* Need to get more random.  */
              gcry_randomize (buffer+32, 8, GCRY_STRONG_RANDOM);
              j = 0;
            }
          buffer[i] = buffer[32+j];
          j++;
        }
    }

  /* Store the key.  */
  append_tuple (mb, KEYBLOB_TAG_ENCKEY, buffer, 32);

  /* Free the temporary buffer.  */
  wipememory (buffer, 32+8);  /*  A failsafe extra wiping.  */
  xfree (buffer);

  return 0;
}
Пример #18
0
static void
fpm_unrotate(gchar* field, gint len)
{
  gint num_blocks;
  gchar* tmp;
  gint b, i;

  g_assert(blocksize>0);
  num_blocks = len/blocksize;
  g_assert(len==num_blocks*blocksize);
  tmp=g_malloc0(len+1);
  for(b=0;b<num_blocks;b++)
  {
    for(i=0;i<blocksize;i++) tmp[i*num_blocks+b] = field[b*blocksize+i];
  }
  memcpy(field, tmp, len);
  wipememory(tmp, len);
  g_free(tmp);
}
Пример #19
0
gchar*
fpm_encrypt_field_var(	void* context,
                        gchar* plaintext)
{
  gint num_blocks, len;
  gchar* cipher_field;
  gchar* plain_field;

  num_blocks = (strlen(plaintext)/(blocksize-1))+1;
  len = num_blocks*blocksize;
  plain_field = g_malloc0(len+1);
  strncpy(plain_field, plaintext, len);
  cipher_field = g_malloc0((len*2)+1);

  fpm_encrypt_field(context, cipher_field, plain_field, num_blocks*blocksize);
  wipememory(plain_field, len);
  g_free(plain_field);

  return(cipher_field);
}
Пример #20
0
static void
salsa20_setiv (void *context, const byte *iv, unsigned int ivlen)
{
  SALSA20_context_t *ctx = (SALSA20_context_t *)context;
  byte tmp[SALSA20_IV_SIZE];

  if (iv && ivlen != SALSA20_IV_SIZE)
    log_info ("WARNING: salsa20_setiv: bad ivlen=%u\n", ivlen);

  if (!iv || ivlen != SALSA20_IV_SIZE)
    memset (tmp, 0, sizeof(tmp));
  else
    memcpy (tmp, iv, SALSA20_IV_SIZE);

  ctx->ivsetup (ctx, tmp);

  /* Reset the unused pad bytes counter.  */
  ctx->unused = 0;

  wipememory (tmp, sizeof(tmp));
}
Пример #21
0
/****************
 * Release resource of the given SEXP object.
 */
void
gcry_sexp_release( gcry_sexp_t sexp )
{
  if (sexp)
    {
      if (gcry_is_secure (sexp))
        {
          /* Extra paranoid wiping. */
          const byte *p = sexp->d;
          int type;

          while ( (type = *p) != ST_STOP )
            {
              p++;
              switch ( type )
                {
                case ST_OPEN:
                  break;
                case ST_CLOSE:
                  break;
                case ST_DATA:
                  {
                    DATALEN n;
                    memcpy ( &n, p, sizeof n );
                    p += sizeof n;
                    p += n;
                  }
                  break;
                default:
                  break;
                }
            }
          wipememory (sexp->d, p - sexp->d);
        }
      gcry_free ( sexp );
    }
}
Пример #22
0
/* Bulk encryption of complete blocks in CTR mode.  This function is only
   intended for the bulk encryption feature of cipher.c.  CTR is expected to be
   of size BLOWFISH_BLOCKSIZE. */
void
_gcry_blowfish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
		       const void *inbuf_arg, size_t nblocks)
{
  BLOWFISH_context *ctx = context;
  unsigned char *outbuf = outbuf_arg;
  const unsigned char *inbuf = inbuf_arg;
  unsigned char tmpbuf[BLOWFISH_BLOCKSIZE];
  int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE;
  int i;

#ifdef USE_AMD64_ASM
  {
    if (nblocks >= 4)
      burn_stack_depth += 5 * sizeof(void*);

    /* Process data in 4 block chunks. */
    while (nblocks >= 4)
      {
        _gcry_blowfish_amd64_ctr_enc(ctx, outbuf, inbuf, ctr);

        nblocks -= 4;
        outbuf += 4 * BLOWFISH_BLOCKSIZE;
        inbuf  += 4 * BLOWFISH_BLOCKSIZE;
      }

    /* Use generic code to handle smaller chunks... */
    /* TODO: use caching instead? */
  }
#elif defined(USE_ARM_ASM)
  {
    /* Process data in 2 block chunks. */
    while (nblocks >= 2)
      {
        _gcry_blowfish_arm_ctr_enc(ctx, outbuf, inbuf, ctr);

        nblocks -= 2;
        outbuf += 2 * BLOWFISH_BLOCKSIZE;
        inbuf  += 2 * BLOWFISH_BLOCKSIZE;
      }

    /* Use generic code to handle smaller chunks... */
    /* TODO: use caching instead? */
  }
#endif

  for ( ;nblocks; nblocks-- )
    {
      /* Encrypt the counter. */
      do_encrypt_block(ctx, tmpbuf, ctr);
      /* XOR the input with the encrypted counter and store in output.  */
      buf_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE);
      outbuf += BLOWFISH_BLOCKSIZE;
      inbuf  += BLOWFISH_BLOCKSIZE;
      /* Increment the counter.  */
      for (i = BLOWFISH_BLOCKSIZE; i > 0; i--)
        {
          ctr[i-1]++;
          if (ctr[i-1])
            break;
        }
    }

  wipememory(tmpbuf, sizeof(tmpbuf));
  _gcry_burn_stack(burn_stack_depth);
}
Пример #23
0
/* Include the implementation of map_spwq_error.  */
MAP_SPWQ_ERROR_IMPL


static void
preset_passphrase (const char *keygrip)
{
  int  rc;
  char *line;
  /* FIXME: Use secure memory.  */
  char passphrase[500];
  char *passphrase_esc;

  if (!opt_passphrase)
    {
      rc = read (0, passphrase, sizeof (passphrase) - 1);
      if (rc < 0)
        {
          log_error ("reading passphrase failed: %s\n",
                     gpg_strerror (gpg_error_from_syserror ()));
          return;
        }
      passphrase[rc] = '\0';
      line = strchr (passphrase, '\n');
      if (line)
        {
          if (line > passphrase && line[-1] == '\r')
            line--;
          *line = '\0';
        }

      /* FIXME: How to handle empty passwords?  */
    }

  {
    const char *s = opt_passphrase ? opt_passphrase : passphrase;
    passphrase_esc = bin2hex (s, strlen (s), NULL);
  }
  if (!passphrase_esc)
    {
      log_error ("can not escape string: %s\n",
		 gpg_strerror (gpg_error_from_syserror ()));
      return;
    }

  rc = asprintf (&line, "PRESET_PASSPHRASE %s -1 %s\n", keygrip,
		 passphrase_esc);
  wipememory (passphrase_esc, strlen (passphrase_esc));
  xfree (passphrase_esc);

  if (rc < 0)
    {
      log_error ("caching passphrase failed: %s\n",
		 gpg_strerror (gpg_error_from_syserror ()));
      return;
    }
  if (!opt_passphrase)
    wipememory (passphrase, sizeof (passphrase));

  rc = map_spwq_error (simple_query (line));
  if (rc)
    {
      log_error ("caching passphrase failed: %s\n", gpg_strerror (rc));
      return;
    }

  wipememory (line, strlen (line));
  xfree (line);
}
Пример #24
0
/* Bulk decryption of complete blocks in CBC mode.  This function is only
   intended for the bulk encryption feature of cipher.c. */
void
_gcry_camellia_cbc_dec(void *context, unsigned char *iv,
                       void *outbuf_arg, const void *inbuf_arg,
                       size_t nblocks)
{
  CAMELLIA_context *ctx = context;
  unsigned char *outbuf = outbuf_arg;
  const unsigned char *inbuf = inbuf_arg;
  unsigned char savebuf[CAMELLIA_BLOCK_SIZE];
  int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size;

#ifdef USE_AESNI_AVX2
  if (ctx->use_aesni_avx2)
    {
      int did_use_aesni_avx2 = 0;

      /* Process data in 32 block chunks. */
      while (nblocks >= 32)
        {
          _gcry_camellia_aesni_avx2_cbc_dec(ctx, outbuf, inbuf, iv);

          nblocks -= 32;
          outbuf += 32 * CAMELLIA_BLOCK_SIZE;
          inbuf  += 32 * CAMELLIA_BLOCK_SIZE;
          did_use_aesni_avx2 = 1;
        }

      if (did_use_aesni_avx2)
        {
          int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 +
                                        2 * sizeof(void *) + ASM_EXTRA_STACK;;

          if (burn_stack_depth < avx2_burn_stack_depth)
            burn_stack_depth = avx2_burn_stack_depth;
        }

      /* Use generic code to handle smaller chunks... */
    }
#endif

#ifdef USE_AESNI_AVX
  if (ctx->use_aesni_avx)
    {
      int did_use_aesni_avx = 0;

      /* Process data in 16 block chunks. */
      while (nblocks >= 16)
        {
          _gcry_camellia_aesni_avx_cbc_dec(ctx, outbuf, inbuf, iv);

          nblocks -= 16;
          outbuf += 16 * CAMELLIA_BLOCK_SIZE;
          inbuf  += 16 * CAMELLIA_BLOCK_SIZE;
          did_use_aesni_avx = 1;
        }

      if (did_use_aesni_avx)
        {
          int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE +
                                       2 * sizeof(void *) + ASM_EXTRA_STACK;

          if (burn_stack_depth < avx_burn_stack_depth)
            burn_stack_depth = avx_burn_stack_depth;
        }

      /* Use generic code to handle smaller chunks... */
    }
#endif

  for ( ;nblocks; nblocks-- )
    {
      /* INBUF is needed later and it may be identical to OUTBUF, so store
         the intermediate result to SAVEBUF.  */
      Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, savebuf);

      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAMELLIA_BLOCK_SIZE);
      inbuf += CAMELLIA_BLOCK_SIZE;
      outbuf += CAMELLIA_BLOCK_SIZE;
    }

  wipememory(savebuf, sizeof(savebuf));
  _gcry_burn_stack(burn_stack_depth);
}
Пример #25
0
/* Bulk encryption of complete blocks in CTR mode.  This function is only
   intended for the bulk encryption feature of cipher.c.  CTR is expected to be
   of size CAMELLIA_BLOCK_SIZE. */
void
_gcry_camellia_ctr_enc(void *context, unsigned char *ctr,
                       void *outbuf_arg, const void *inbuf_arg,
                       size_t nblocks)
{
  CAMELLIA_context *ctx = context;
  unsigned char *outbuf = outbuf_arg;
  const unsigned char *inbuf = inbuf_arg;
  unsigned char tmpbuf[CAMELLIA_BLOCK_SIZE];
  int burn_stack_depth = CAMELLIA_encrypt_stack_burn_size;
  int i;

#ifdef USE_AESNI_AVX2
  if (ctx->use_aesni_avx2)
    {
      int did_use_aesni_avx2 = 0;

      /* Process data in 32 block chunks. */
      while (nblocks >= 32)
        {
          _gcry_camellia_aesni_avx2_ctr_enc(ctx, outbuf, inbuf, ctr);

          nblocks -= 32;
          outbuf += 32 * CAMELLIA_BLOCK_SIZE;
          inbuf  += 32 * CAMELLIA_BLOCK_SIZE;
          did_use_aesni_avx2 = 1;
        }

      if (did_use_aesni_avx2)
        {
          int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 +
                                        2 * sizeof(void *) + ASM_EXTRA_STACK;

          if (burn_stack_depth < avx2_burn_stack_depth)
            burn_stack_depth = avx2_burn_stack_depth;
        }

      /* Use generic code to handle smaller chunks... */
      /* TODO: use caching instead? */
    }
#endif

#ifdef USE_AESNI_AVX
  if (ctx->use_aesni_avx)
    {
      int did_use_aesni_avx = 0;

      /* Process data in 16 block chunks. */
      while (nblocks >= 16)
        {
          _gcry_camellia_aesni_avx_ctr_enc(ctx, outbuf, inbuf, ctr);

          nblocks -= 16;
          outbuf += 16 * CAMELLIA_BLOCK_SIZE;
          inbuf  += 16 * CAMELLIA_BLOCK_SIZE;
          did_use_aesni_avx = 1;
        }

      if (did_use_aesni_avx)
        {
          int avx_burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE +
                                       2 * sizeof(void *) + ASM_EXTRA_STACK;

          if (burn_stack_depth < avx_burn_stack_depth)
            burn_stack_depth = avx_burn_stack_depth;
        }

      /* Use generic code to handle smaller chunks... */
      /* TODO: use caching instead? */
    }
#endif

  for ( ;nblocks; nblocks-- )
    {
      /* Encrypt the counter. */
      Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf);
      /* XOR the input with the encrypted counter and store in output.  */
      buf_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE);
      outbuf += CAMELLIA_BLOCK_SIZE;
      inbuf  += CAMELLIA_BLOCK_SIZE;
      /* Increment the counter.  */
      for (i = CAMELLIA_BLOCK_SIZE; i > 0; i--)
        {
          ctr[i-1]++;
          if (ctr[i-1])
            break;
        }
    }

  wipememory(tmpbuf, sizeof(tmpbuf));
  _gcry_burn_stack(burn_stack_depth);
}
Пример #26
0
/* Return the secret key as an S-Exp in RESULT after locating it using
   the GRIP.  Stores NULL at RESULT if the operation shall be diverted
   to a token; in this case an allocated S-expression with the
   shadow_info part from the file is stored at SHADOW_INFO.
   CACHE_MODE defines now the cache shall be used.  DESC_TEXT may be
   set to present a custom description for the pinentry.  LOOKUP_TTL
   is an optional function to convey a TTL to the cache manager; we do
   not simply pass the TTL value because the value is only needed if an
   unprotect action was needed and looking up the TTL may have some
   overhead (e.g. scanning the sshcontrol file). */
gpg_error_t
agent_key_from_file (ctrl_t ctrl, const char *desc_text,
                     const unsigned char *grip, unsigned char **shadow_info,
                     cache_mode_t cache_mode, lookup_ttl_t lookup_ttl,
                     gcry_sexp_t *result)
{
  int rc;
  unsigned char *buf;
  size_t len, buflen, erroff;
  gcry_sexp_t s_skey;
  int got_shadow_info = 0;

  *result = NULL;
  if (shadow_info)
    *shadow_info = NULL;

  rc = read_key_file (grip, &s_skey);
  if (rc)
    return rc;

  /* For use with the protection functions we also need the key as an
     canonical encoded S-expression in a buffer.  Create this buffer
     now.  */
  rc = make_canon_sexp (s_skey, &buf, &len);
  if (rc)
    return rc;

  switch (agent_private_key_type (buf))
    {
    case PRIVATE_KEY_CLEAR:
      break; /* no unprotection needed */
    case PRIVATE_KEY_PROTECTED:
      {
	char *desc_text_final;
	char *comment = NULL;

        /* Note, that we will take the comment as a C string for
           display purposes; i.e. all stuff beyond a Nul character is
           ignored.  */
        {
          gcry_sexp_t comment_sexp;

          comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
          if (comment_sexp)
            comment = gcry_sexp_nth_string (comment_sexp, 1);
          gcry_sexp_release (comment_sexp);
        }

        desc_text_final = NULL;
	if (desc_text)
          rc = modify_description (desc_text, comment? comment:"", s_skey,
                                   &desc_text_final);
        gcry_free (comment);

	if (!rc)
	  {
	    rc = unprotect (ctrl, desc_text_final, &buf, grip,
                            cache_mode, lookup_ttl);
	    if (rc)
	      log_error ("failed to unprotect the secret key: %s\n",
			 gpg_strerror (rc));
	  }

	xfree (desc_text_final);
      }
      break;
    case PRIVATE_KEY_SHADOWED:
      if (shadow_info)
        {
          const unsigned char *s;
          size_t n;

          rc = agent_get_shadow_info (buf, &s);
          if (!rc)
            {
              n = gcry_sexp_canon_len (s, 0, NULL,NULL);
              assert (n);
              *shadow_info = xtrymalloc (n);
              if (!*shadow_info)
                rc = out_of_core ();
              else
                {
                  memcpy (*shadow_info, s, n);
                  rc = 0;
                  got_shadow_info = 1;
                }
            }
          if (rc)
            log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
        }
      else
        rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
      break;
    default:
      log_error ("invalid private key format\n");
      rc = gpg_error (GPG_ERR_BAD_SECKEY);
      break;
    }
  gcry_sexp_release (s_skey);
  s_skey = NULL;
  if (rc || got_shadow_info)
    {
      xfree (buf);
      return rc;
    }

  buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL);
  rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
  wipememory (buf, buflen);
  xfree (buf);
  if (rc)
    {
      log_error ("failed to build S-Exp (off=%u): %s\n",
                 (unsigned int)erroff, gpg_strerror (rc));
      return rc;
    }

  *result = s_skey;
  return 0;
}
Пример #27
0
/* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
   should be the hex encoded keygrip of that key to be used with the
   caching mechanism. DESC_TEXT may be set to override the default
   description used for the pinentry.  If LOOKUP_TTL is given this
   function is used to lookup the default ttl. */
static int
unprotect (ctrl_t ctrl, const char *desc_text,
           unsigned char **keybuf, const unsigned char *grip,
           cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
{
  struct pin_entry_info_s *pi;
  struct try_unprotect_arg_s arg;
  int rc;
  unsigned char *result;
  size_t resultlen;
  char hexgrip[40+1];

  bin2hex (grip, 20, hexgrip);

  /* First try to get it from the cache - if there is none or we can't
     unprotect it, we fall back to ask the user */
  if (cache_mode != CACHE_MODE_IGNORE)
    {
      void *cache_marker;
      const char *pw;

    retry:
      pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
      if (pw)
        {
          rc = agent_unprotect (*keybuf, pw, NULL, &result, &resultlen);
          agent_unlock_cache_entry (&cache_marker);
          if (!rc)
            {
              xfree (*keybuf);
              *keybuf = result;
              return 0;
            }
          rc  = 0;
        }

      /* If the pinentry is currently in use, we wait up to 60 seconds
         for it to close and check the cache again.  This solves a common
         situation where several requests for unprotecting a key have
         been made but the user is still entering the passphrase for
         the first request.  Because all requests to agent_askpin are
         serialized they would then pop up one after the other to
         request the passphrase - despite that the user has already
         entered it and is then available in the cache.  This
         implementation is not race free but in the worst case the
         user has to enter the passphrase only once more. */
      if (pinentry_active_p (ctrl, 0))
        {
          /* Active - wait */
          if (!pinentry_active_p (ctrl, 60))
            {
              /* We need to give the other thread a chance to actually put
                 it into the cache. */
              pth_sleep (1);
              goto retry;
            }
          /* Timeout - better call pinentry now the plain way. */
        }
    }

  pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
  if (!pi)
    return gpg_error_from_syserror ();
  pi->max_length = 100;
  pi->min_digits = 0;  /* we want a real passphrase */
  pi->max_digits = 16;
  pi->max_tries = 3;
  pi->check_cb = try_unprotect_cb;
  arg.ctrl = ctrl;
  arg.protected_key = *keybuf;
  arg.unprotected_key = NULL;
  arg.change_required = 0;
  pi->check_cb_arg = &arg;

  rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
  if (!rc)
    {
      assert (arg.unprotected_key);
      if (arg.change_required)
        {
          size_t canlen, erroff;
          gcry_sexp_t s_skey;

          assert (arg.unprotected_key);
          canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
          rc = gcry_sexp_sscan (&s_skey, &erroff,
                                (char*)arg.unprotected_key, canlen);
          if (rc)
            {
              log_error ("failed to build S-Exp (off=%u): %s\n",
                         (unsigned int)erroff, gpg_strerror (rc));
              wipememory (arg.unprotected_key, canlen);
              xfree (arg.unprotected_key);
              xfree (pi);
              return rc;
            }
          rc = agent_protect_and_store (ctrl, s_skey);
          gcry_sexp_release (s_skey);
          if (rc)
            {
              log_error ("changing the passphrase failed: %s\n",
                         gpg_strerror (rc));
              wipememory (arg.unprotected_key, canlen);
              xfree (arg.unprotected_key);
              xfree (pi);
              return rc;
            }
        }
      else
        agent_put_cache (hexgrip, cache_mode, pi->pin,
                         lookup_ttl? lookup_ttl (hexgrip) : 0);
      xfree (*keybuf);
      *keybuf = arg.unprotected_key;
    }
  xfree (pi);
  return rc;
}
Пример #28
0
/* Bulk decryption of complete blocks in CBC mode.  This function is only
   intended for the bulk encryption feature of cipher.c. */
void
_gcry_serpent_cbc_dec(void *context, unsigned char *iv,
                      void *outbuf_arg, const void *inbuf_arg,
                      size_t nblocks)
{
  serpent_context_t *ctx = context;
  unsigned char *outbuf = outbuf_arg;
  const unsigned char *inbuf = inbuf_arg;
  unsigned char savebuf[sizeof(serpent_block_t)];
  int burn_stack_depth = 2 * sizeof (serpent_block_t);

#ifdef USE_AVX2
  if (ctx->use_avx2)
    {
      int did_use_avx2 = 0;

      /* Process data in 16 block chunks. */
      while (nblocks >= 16)
        {
          _gcry_serpent_avx2_cbc_dec(ctx, outbuf, inbuf, iv);

          nblocks -= 16;
          outbuf += 16 * sizeof(serpent_block_t);
          inbuf  += 16 * sizeof(serpent_block_t);
          did_use_avx2 = 1;
        }

      if (did_use_avx2)
        {
          /* serpent-avx2 assembly code does not use stack */
          if (nblocks == 0)
            burn_stack_depth = 0;
        }

      /* Use generic/sse2 code to handle smaller chunks... */
    }
#endif

#ifdef USE_SSE2
  {
    int did_use_sse2 = 0;

    /* Process data in 8 block chunks. */
    while (nblocks >= 8)
      {
        _gcry_serpent_sse2_cbc_dec(ctx, outbuf, inbuf, iv);

        nblocks -= 8;
        outbuf += 8 * sizeof(serpent_block_t);
        inbuf  += 8 * sizeof(serpent_block_t);
        did_use_sse2 = 1;
      }

    if (did_use_sse2)
      {
        /* serpent-sse2 assembly code does not use stack */
        if (nblocks == 0)
          burn_stack_depth = 0;
      }

    /* Use generic code to handle smaller chunks... */
  }
#endif

#ifdef USE_NEON
  if (ctx->use_neon)
    {
      int did_use_neon = 0;

      /* Process data in 8 block chunks. */
      while (nblocks >= 8)
        {
          _gcry_serpent_neon_cbc_dec(ctx, outbuf, inbuf, iv);

          nblocks -= 8;
          outbuf += 8 * sizeof(serpent_block_t);
          inbuf  += 8 * sizeof(serpent_block_t);
          did_use_neon = 1;
        }

      if (did_use_neon)
        {
          /* serpent-neon assembly code does not use stack */
          if (nblocks == 0)
            burn_stack_depth = 0;
        }

      /* Use generic code to handle smaller chunks... */
    }
#endif

  for ( ;nblocks; nblocks-- )
    {
      /* INBUF is needed later and it may be identical to OUTBUF, so store
         the intermediate result to SAVEBUF.  */
      serpent_decrypt_internal (ctx, inbuf, savebuf);

      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, sizeof(serpent_block_t));
      inbuf += sizeof(serpent_block_t);
      outbuf += sizeof(serpent_block_t);
    }

  wipememory(savebuf, sizeof(savebuf));
  _gcry_burn_stack(burn_stack_depth);
}
/****************
 * Encrypt the file with the given userids (or ask if none
 * is supplied).
 */
int
encode_crypt( const char *filename, STRLIST remusr, int use_symkey )
{
    IOBUF inp = NULL, out = NULL;
    PACKET pkt;
    PKT_plaintext *pt = NULL;
    DEK *symkey_dek = NULL;
    STRING2KEY *symkey_s2k = NULL;
    int rc = 0, rc2 = 0;
    u32 filesize;
    cipher_filter_context_t cfx;
    armor_filter_context_t afx;
    compress_filter_context_t zfx;
    text_filter_context_t tfx;
    progress_filter_context_t pfx;
    PK_LIST pk_list,work_list;
    int do_compress = opt.compress_algo && !RFC1991;

    memset( &cfx, 0, sizeof cfx);
    memset( &afx, 0, sizeof afx);
    memset( &zfx, 0, sizeof zfx);
    memset( &tfx, 0, sizeof tfx);
    init_packet(&pkt);

    if(use_symkey
       && (rc=setup_symkey(&symkey_s2k,&symkey_dek)))
      return rc;

    if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
	return rc;

    if(PGP2) {
      for(work_list=pk_list; work_list; work_list=work_list->next)
	if(!(is_RSA(work_list->pk->pubkey_algo) &&
	     nbits_from_pk(work_list->pk)<=2048))
	  {
	    log_info(_("you can only encrypt to RSA keys of 2048 bits or "
		       "less in --pgp2 mode\n"));
	    compliance_failure();
	    break;
	  }
    }

    /* prepare iobufs */
    inp = iobuf_open(filename);
    if (inp)
      iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */
    if (inp && is_secured_file (iobuf_get_fd (inp)))
      {
        iobuf_close (inp);
        inp = NULL;
        errno = EPERM;
      }
    if( !inp ) {
	log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]",
					strerror(errno) );
	rc = G10ERR_OPEN_FILE;
	goto leave;
    }
    else if( opt.verbose )
	log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");

    handle_progress (&pfx, inp, filename);

    if( opt.textmode )
	iobuf_push_filter( inp, text_filter, &tfx );

    if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
	goto leave;

    if( opt.armor )
	iobuf_push_filter( out, armor_filter, &afx );

    /* create a session key */
    cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
    if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
	cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL);
	/* The only way select_algo_from_prefs can fail here is when
           mixing v3 and v4 keys, as v4 keys have an implicit
           preference entry for 3DES, and the pk_list cannot be empty.
           In this case, use 3DES anyway as it's the safest choice -
           perhaps the v3 key is being used in an OpenPGP
           implementation and we know that the implementation behind
           any v4 key can handle 3DES. */
	if( cfx.dek->algo == -1 ) {
	    cfx.dek->algo = CIPHER_ALGO_3DES;

	    if( PGP2 ) {
	      log_info(_("unable to use the IDEA cipher for all of the keys "
			 "you are encrypting to.\n"));
	      compliance_failure();
	    }
	}
    }
    else {
      if(!opt.expert &&
	 select_algo_from_prefs(pk_list,PREFTYPE_SYM,
				opt.def_cipher_algo,NULL)!=opt.def_cipher_algo)
	log_info(_("WARNING: forcing symmetric cipher %s (%d)"
		   " violates recipient preferences\n"),
		 cipher_algo_to_string(opt.def_cipher_algo),
		 opt.def_cipher_algo);

      cfx.dek->algo = opt.def_cipher_algo;
    }

    cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo);

    /* Only do the is-file-already-compressed check if we are using a
       MDC.  This forces compressed files to be re-compressed if we do
       not have a MDC to give some protection against chosen
       ciphertext attacks. */

    if (do_compress && cfx.dek->use_mdc && is_file_compressed(filename, &rc2) )
      {
        if (opt.verbose)
          log_info(_("`%s' already compressed\n"), filename);
        do_compress = 0;        
      }
    if (rc2)
      {
        rc = rc2;
        goto leave;
      }

    make_session_key( cfx.dek );
    if( DBG_CIPHER )
	log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );

    rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
    if( rc  )
	goto leave;

    /* We put the passphrase (if any) after any public keys as this
       seems to be the most useful on the recipient side - there is no
       point in prompting a user for a passphrase if they have the
       secret key needed to decrypt. */
    if(use_symkey && (rc=write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out)))
      goto leave;

    if (!opt.no_literal) {
	/* setup the inner packet */
	if( filename || opt.set_filename ) {
	    char *s = make_basename( opt.set_filename ? opt.set_filename
						      : filename,
				     iobuf_get_real_fname( inp ) );
	    pt = xmalloc( sizeof *pt + strlen(s) - 1 );
	    pt->namelen = strlen(s);
	    memcpy(pt->name, s, pt->namelen );
	    xfree(s);
	}
	else { /* no filename */
	    pt = xmalloc( sizeof *pt - 1 );
	    pt->namelen = 0;
	}
    }

    if (!iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
      {
        off_t tmpsize;
        int overflow;

	if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
             && !overflow )
          log_info(_("WARNING: `%s' is an empty file\n"), filename );
        /* We can't encode the length of very large files because
           OpenPGP uses only 32 bit for file sizes.  So if the the
           size of a file is larger than 2^32 minus some bytes for
           packet headers, we switch to partial length encoding. */
        if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
          filesize = tmpsize;
        else
          filesize = 0;
      }
    else
      filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */

    if (!opt.no_literal) {
	pt->timestamp = make_timestamp();
	pt->mode = opt.textmode ? 't' : 'b';
	pt->len = filesize;
	pt->new_ctb = !pt->len && !RFC1991;
	pt->buf = inp;
	pkt.pkttype = PKT_PLAINTEXT;
	pkt.pkt.plaintext = pt;
	cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
    }
    else
	cfx.datalen = filesize && !do_compress ? filesize : 0;

    /* register the cipher filter */
    iobuf_push_filter( out, cipher_filter, &cfx );

    /* register the compress filter */
    if( do_compress ) {
	int compr_algo = opt.compress_algo;

	if(compr_algo==-1)
	  {
	    if((compr_algo=
		select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
	      compr_algo=DEFAULT_COMPRESS_ALGO;
	    /* Theoretically impossible to get here since uncompressed
	       is implicit. */
	  }
	else if(!opt.expert &&
		select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
				       compr_algo,NULL)!=compr_algo)
	  log_info(_("WARNING: forcing compression algorithm %s (%d)"
		     " violates recipient preferences\n"),
		   compress_algo_to_string(compr_algo),compr_algo);

	/* algo 0 means no compression */
	if( compr_algo )
	  {
            if (cfx.dek && cfx.dek->use_mdc)
              zfx.new_ctb = 1;
	    push_compress_filter(out,&zfx,compr_algo);
	  }
    }

    /* do the work */
    if (!opt.no_literal) {
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build_packet failed: %s\n", g10_errstr(rc) );
    }
    else {
	/* user requested not to create a literal packet, so we copy
           the plain data */
	byte copy_buffer[4096];
	int  bytes_copied;
	while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
	    if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
		rc = G10ERR_WRITE_FILE;
		log_error("copying input to output failed: %s\n",
                          g10_errstr(rc) );
		break;
	    }
	wipememory(copy_buffer, 4096); /* burn buffer */
    }

    /* finish the stuff */
  leave:
    iobuf_close(inp);
    if( rc )
	iobuf_cancel(out);
    else {
	iobuf_close(out); /* fixme: check returncode */
        write_status( STATUS_END_ENCRYPTION );
    }
    if( pt )
	pt->buf = NULL;
    free_packet(&pkt);
    xfree(cfx.dek);
    xfree(symkey_dek);
    xfree(symkey_s2k);
    release_pk_list( pk_list );
    return rc;
}
/* We don't want to use use_seskey yet because older gnupg versions
   can't handle it, and there isn't really any point unless we're
   making a message that can be decrypted by a public key or
   passphrase. */
static int
encode_simple( const char *filename, int mode, int use_seskey )
{
    IOBUF inp, out;
    PACKET pkt;
    PKT_plaintext *pt = NULL;
    STRING2KEY *s2k = NULL;
    byte enckey[33];
    int rc = 0;
    int seskeylen = 0;
    u32 filesize;
    cipher_filter_context_t cfx;
    armor_filter_context_t afx;
    compress_filter_context_t zfx;
    text_filter_context_t tfx;
    progress_filter_context_t pfx;
    int do_compress = !RFC1991 && default_compress_algo();

    memset( &cfx, 0, sizeof cfx);
    memset( &afx, 0, sizeof afx);
    memset( &zfx, 0, sizeof zfx);
    memset( &tfx, 0, sizeof tfx);
    init_packet(&pkt);
    
    /* prepare iobufs */
    inp = iobuf_open(filename);
    if (inp)
      iobuf_ioctl (inp,3,1,NULL); /* disable fd caching */
    if (inp && is_secured_file (iobuf_get_fd (inp)))
      {
        iobuf_close (inp);
        inp = NULL;
        errno = EPERM;
      }
    if( !inp ) {
	log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]",
                  strerror(errno) );
	return G10ERR_OPEN_FILE;
    }

    handle_progress (&pfx, inp, filename);

    if( opt.textmode )
	iobuf_push_filter( inp, text_filter, &tfx );

    /* Due the the fact that we use don't use an IV to encrypt the
       session key we can't use the new mode with RFC1991 because
       it has no S2K salt. RFC1991 always uses simple S2K. */
    if ( RFC1991 && use_seskey )
        use_seskey = 0;
    
    cfx.dek = NULL;
    if( mode ) {
	s2k = xmalloc_clear( sizeof *s2k );
	s2k->mode = RFC1991? 0:opt.s2k_mode;
	s2k->hash_algo=S2K_DIGEST_ALGO;
	cfx.dek = passphrase_to_dek( NULL, 0,
				     default_cipher_algo(), s2k, 2,
                                     NULL, NULL);
	if( !cfx.dek || !cfx.dek->keylen ) {
	    rc = G10ERR_PASSPHRASE;
	    xfree(cfx.dek);
	    xfree(s2k);
	    iobuf_close(inp);
	    log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
	    return rc;
	}
        if (use_seskey && s2k->mode != 1 && s2k->mode != 3) {
            use_seskey = 0;
            log_info (_("can't use a symmetric ESK packet "
                        "due to the S2K mode\n"));
        }

        if ( use_seskey )
	  {
	    DEK *dek = NULL;
            seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
            encode_seskey( cfx.dek, &dek, enckey );
            xfree( cfx.dek ); cfx.dek = dek;
	  }

	if(opt.verbose)
	  log_info(_("using cipher %s\n"),
		   cipher_algo_to_string(cfx.dek->algo));

	cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
    }

    if (do_compress && cfx.dek && cfx.dek->use_mdc
	&& is_file_compressed(filename, &rc))
      {
        if (opt.verbose)
          log_info(_("`%s' already compressed\n"), filename);
        do_compress = 0;        
      }

    if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
	iobuf_cancel(inp);
	xfree(cfx.dek);
	xfree(s2k);
	return rc;
    }

    if( opt.armor )
	iobuf_push_filter( out, armor_filter, &afx );

    if( s2k && !RFC1991 ) {
	PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 );
	enc->version = 4;
	enc->cipher_algo = cfx.dek->algo;
	enc->s2k = *s2k;
        if ( use_seskey && seskeylen ) {
            enc->seskeylen = seskeylen + 1; /* algo id */
            memcpy( enc->seskey, enckey, seskeylen + 1 );
        }
	pkt.pkttype = PKT_SYMKEY_ENC;
	pkt.pkt.symkey_enc = enc;
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
	xfree(enc);
    }

    if (!opt.no_literal)
      pt=setup_plaintext_name(filename,inp);

    /* Note that PGP 5 has problems decrypting symmetrically encrypted
       data if the file length is in the inner packet. It works when
       only partial length headers are use.  In the past, we always
       used partial body length here, but since PGP 2, PGP 6, and PGP
       7 need the file length, and nobody should be using PGP 5
       nowadays anyway, this is now set to the file length.  Note also
       that this only applies to the RFC-1991 style symmetric
       messages, and not the RFC-2440 style.  PGP 6 and 7 work with
       either partial length or fixed length with the new style
       messages. */

    if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
      {
        off_t tmpsize;
        int overflow;

	if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
             && !overflow )
          log_info(_("WARNING: `%s' is an empty file\n"), filename );
        /* We can't encode the length of very large files because
           OpenPGP uses only 32 bit for file sizes.  So if the the
           size of a file is larger than 2^32 minus some bytes for
           packet headers, we switch to partial length encoding. */
        if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
          filesize = tmpsize;
        else
          filesize = 0;
      }
    else
      filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */

    if (!opt.no_literal) {
	pt->timestamp = make_timestamp();
	pt->mode = opt.textmode? 't' : 'b';
	pt->len = filesize;
	pt->new_ctb = !pt->len && !RFC1991;
	pt->buf = inp;
	pkt.pkttype = PKT_PLAINTEXT;
	pkt.pkt.plaintext = pt;
	cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
    }
    else
      {
        cfx.datalen = filesize && !do_compress ? filesize : 0;
        pkt.pkttype = 0;
        pkt.pkt.generic = NULL;
      }

    /* register the cipher filter */
    if( mode )
	iobuf_push_filter( out, cipher_filter, &cfx );
    /* register the compress filter */
    if( do_compress )
      {
        if (cfx.dek && cfx.dek->use_mdc)
          zfx.new_ctb = 1;
	push_compress_filter(out,&zfx,default_compress_algo());
      }

    /* do the work */
    if (!opt.no_literal) {
	if( (rc = build_packet( out, &pkt )) )
	    log_error("build_packet failed: %s\n", g10_errstr(rc) );
    }
    else {
	/* user requested not to create a literal packet,
	 * so we copy the plain data */
	byte copy_buffer[4096];
	int  bytes_copied;
	while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
	    if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
		rc = G10ERR_WRITE_FILE;
		log_error("copying input to output failed: %s\n", g10_errstr(rc) );
		break;
	    }
	wipememory(copy_buffer, 4096); /* burn buffer */
    }

    /* finish the stuff */
    iobuf_close(inp);
    if (rc)
	iobuf_cancel(out);
    else {
	iobuf_close(out); /* fixme: check returncode */
        if (mode)
            write_status( STATUS_END_ENCRYPTION );
    }
    if (pt)
	pt->buf = NULL;
    free_packet(&pkt);
    xfree(cfx.dek);
    xfree(s2k);
    return rc;
}