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 (); else { 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); else { gcry_md_write (md, s2ksalt, 8); count -= 8; gcry_md_write (md, passphrase, count); } } else 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; } gcry_md_close(md); 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 -- Werner Koch The GnuPG Experts http://g10code.com Free Software Foundation Europe http://fsfeurope.org