parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
		 PACKET * packet)
{
  PKT_symkey_enc *k;
  int rc = 0;
  int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen;

  if (pktlen < 4)
    {
      log_error ("packet(%d) too short\n", pkttype);
      if (list_mode)
        es_fprintf (listfp, ":symkey enc packet: [too short]\n");
      rc = gpg_error (GPG_ERR_INV_PACKET);
      goto leave;
    }
  version = iobuf_get_noeof (inp);
  pktlen--;
  if (version != 4)
    {
      log_error ("packet(%d) with unknown version %d\n", pkttype, version);
      if (list_mode)
        es_fprintf (listfp, ":symkey enc packet: [unknown version]\n");
      rc = gpg_error (GPG_ERR_INV_PACKET);
      goto leave;
    }
  if (pktlen > 200)
    {				/* (we encode the seskeylen in a byte) */
      log_error ("packet(%d) too large\n", pkttype);
      if (list_mode)
        es_fprintf (listfp, ":symkey enc packet: [too large]\n");
      rc = gpg_error (GPG_ERR_INV_PACKET);
      goto leave;
    }
  cipher_algo = iobuf_get_noeof (inp);
  pktlen--;
  s2kmode = iobuf_get_noeof (inp);
  pktlen--;
  hash_algo = iobuf_get_noeof (inp);
  pktlen--;
  switch (s2kmode)
    {
    case 0: /* Simple S2K.  */
      minlen = 0;
      break;
    case 1: /* Salted S2K.  */
      minlen = 8;
      break;
    case 3: /* Iterated+salted S2K.  */
      minlen = 9;
      break;
    default:
      log_error ("unknown S2K mode %d\n", s2kmode);
      if (list_mode)
        es_fprintf (listfp, ":symkey enc packet: [unknown S2K mode]\n");
      goto leave;
    }
  if (minlen > pktlen)
    {
      log_error ("packet with S2K %d too short\n", s2kmode);
      if (list_mode)
        es_fprintf (listfp, ":symkey enc packet: [too short]\n");
      rc = gpg_error (GPG_ERR_INV_PACKET);
      goto leave;
    }
  seskeylen = pktlen - minlen;
  k = packet->pkt.symkey_enc = xmalloc_clear (sizeof *packet->pkt.symkey_enc
					      + seskeylen - 1);
  k->version = version;
  k->cipher_algo = cipher_algo;
  k->s2k.mode = s2kmode;
  k->s2k.hash_algo = hash_algo;
  if (s2kmode == 1 || s2kmode == 3)
    {
      for (i = 0; i < 8 && pktlen; i++, pktlen--)
	k->s2k.salt[i] = iobuf_get_noeof (inp);
    }
  if (s2kmode == 3)
    {
      k->s2k.count = iobuf_get (inp);
      pktlen--;
    }
  k->seskeylen = seskeylen;
  if (k->seskeylen)
    {
      for (i = 0; i < seskeylen && pktlen; i++, pktlen--)
	k->seskey[i] = iobuf_get_noeof (inp);

      /* What we're watching out for here is a session key decryptor
         with no salt.  The RFC says that using salt for this is a
         MUST. */
      if (s2kmode != 1 && s2kmode != 3)
	log_info (_("WARNING: potentially insecure symmetrically"
		    " encrypted session key\n"));
    }
  assert (!pktlen);

  if (list_mode)
    {
      es_fprintf (listfp,
                  ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d",
                  version, cipher_algo, s2kmode, hash_algo);
      if (seskeylen)
	es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8);
      es_fprintf (listfp, "\n");
      if (s2kmode == 1 || s2kmode == 3)
	{
	  es_fprintf (listfp, "\tsalt ");
          es_write_hexstring (listfp, k->s2k.salt, 8, 0, NULL);
	  if (s2kmode == 3)
	    es_fprintf (listfp, ", count %lu (%lu)",
                        S2K_DECODE_COUNT ((ulong) k->s2k.count),
                        (ulong) k->s2k.count);
	  es_fprintf (listfp, "\n");
	}
    }

 leave:
  iobuf_skip_rest (inp, pktlen, 0);
  return rc;
}