Fwd: KWallet weaknesses

Werner Koch wk at gnupg.org
Mon Dec 8 22:10:15 GMT 2003

On Mon, 8 Dec 2003 20:28:32 +0100, Dirk Mueller said:

> a) You said the passphrase -> key code is bad. Which code should we use 
> instead? Where can we get a working implementation, or verify our own?

Either PKCS#5 or the S2K code from OpenPGP.  Here is an implementation
under the GPL from gnupg-1.9/agent/protect.c derived from gnupg:

/* Transform a passphrase into a suitable key of length KEYLEN and
   store this key in the caller provided buffer KEY.  The caller must
   provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
   that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
   value is 96).
   Returns an error code on failure. 

   Example usage:
      unsigned char salt[8];       
      unsigned char *key;
      size_t keylen;

      gcry_get_nonce (salt, sizeof salt)
      key = gcry_malloc_secure (keylen);
      if (!key)
        rc = out_of_core ();
          rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
                                3, salt, 96, key, keylen);
          if (!rc)
            rc = gcry_cipher_setkey (hd, key, keylen);
          xfree (key);

static int
hash_passphrase (const char *passphrase, int hashalgo,
                 int s2kmode,
                 const unsigned char *s2ksalt,
                 unsigned long s2kcount,
                 unsigned char *key, size_t keylen)
  int rc;
  gcry_md_hd_t md;
  int pass, i;
  int used = 0;
  int pwlen = strlen (passphrase);

  if ( (s2kmode != 0 && s2kmode != 1 && s2kmode != 3)
      || !hashalgo || !keylen || !key || !passphrase)
    return gpg_error (GPG_ERR_INV_VALUE);
  if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
    return gpg_error (GPG_ERR_INV_VALUE);
  rc = gcry_md_open (&md, hashalgo, GCRY_MD_FLAG_SECURE);
  if (rc)
    return rc;

  for (pass=0; used < keylen; pass++)
      if (pass)
          gcry_md_reset (md);
          for (i=0; i < pass; i++) /* preset the hash context */
            gcry_md_putc (md, 0);

      if (s2kmode == 1 || s2kmode == 3)
          int len2 = pwlen + 8;
          unsigned long count = len2;

          if (s2kmode == 3)
              count = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
              if (count < len2)
                count = len2;

          while (count > len2)
              gcry_md_write (md, s2ksalt, 8);
              gcry_md_write (md, passphrase, pwlen);
              count -= len2;
          if (count < 8)
            gcry_md_write (md, s2ksalt, count);
              gcry_md_write (md, s2ksalt, 8);
              count -= 8;
              gcry_md_write (md, passphrase, count);
        gcry_md_write (md, passphrase, pwlen);
      gcry_md_final (md);
      i = gcry_md_get_algo_dlen (hashalgo);
      if (i > keylen - used)
        i = keylen - used;
      memcpy  (key+used, gcry_md_read (md, hashalgo), i);
      used += i;
  return 0;

> b) You said that the version numbers will allow replay attacks. Though I don't 

I talked about a rollback attack, that is at one time you change the
algorithm because a weakness was found in Blowfish and under certain
conditions an attacker might be able to trick you to use Blowfish
again even you are using the modern-ultra-resistant-algorithm.  There
is no immediate need but you should think about it when you allow for
different algorithms.  BTW, even Schneier is not anymore certain of
his Blowfish; all other modern algorithm have meanwhile been better
analyzed than Blowfish.


Werner Koch                                      <wk at gnupg.org>
The GnuPG Experts                                http://g10code.com
Free Software Foundation Europe                  http://fsfeurope.org

More information about the kde-core-devel mailing list