On Sun, Apr 19, 2026 at 08:42:48AM +0200, Alejandro Colomar via Mutt-dev wrote:
On 2026-04-19T07:48:40+0800, Kevin J. McCarthy wrote:
On Sat, Apr 18, 2026 at 08:27:26PM +0200, Alejandro Colomar via Mutt-dev wrote:

/etc/shadow stores a readable ascii encoding, (base64?)  not the raw bytes
themselves.  In this case, md5_buffer() actually generates binary data and
stores it into hash_passwd.

As far as I know (I could be wrong), it stores the raw bytes.  I've
checked the source code of the shadow project, and didn't find anything
that seems to encode the data in any way.  It stores directly whatever
that crypt(3) produces.  Unless crypt(3) itself already gives us an
encoded version of the hash, of course.

The output of md5 is a sequence of 16 bytes, each of which can have values 0-255, right? So it would make sense that if the result of crypt(3) was not encoded somehow, `cat /etc/shadow` (as root of course) would generate garbage in the terminal.

If I have time I'll try to play with it more, but I can confirm that mutt's md5_buffer() generates raw data. In places where mutt wants to use that data as a string, it encodes it, for example in hcache.c L642:

    md5_buffer(folder, strlen(folder), &md5sum);
    mutt_buffer_printf(hcfile,
                       "%02x%02x%02x%02x%02x%02x%02x%02x"
                       "%02x%02x%02x%02x%02x%02x%02x%02x",
                       md5sum[0], md5sum[1], md5sum[2], md5sum[3],
                       md5sum[4], md5sum[5], md5sum[6], md5sum[7],
                       md5sum[8], md5sum[9], md5sum[10], md5sum[11],
                       md5sum[12], md5sum[13], md5sum[14], md5sum[15]);

In any case - even if I am completely wrong - there isn't anything wrong with using memcpy on the result in auth_cram(). The value of 'secret' is further memcpy() below into ipad and opad. AFAIK, AUTH CRAM is supposed to be fed the raw bytes when the secret is md5 digested. See imap/auth_cram.c:


  secret_len = strlen (password);
  chal_len = strlen (challenge);

  /* passwords longer than MD5_BLOCK_LEN bytes are substituted with their MD5
   * digests */
  if (secret_len > MD5_BLOCK_LEN)
  {
    md5_buffer (password, secret_len, hash_passwd);
    memcpy(secret, hash_passwd, MD5_DIGEST_LEN);
    secret_len = MD5_DIGEST_LEN;
  }
  else
    strfcpy ((char *) secret, password, sizeof (secret));

  memset (ipad, 0, sizeof (ipad));
  memset (opad, 0, sizeof (opad));
  memcpy (ipad, secret, secret_len);
  memcpy (opad, secret, secret_len);


--
Kevin J. McCarthy
GPG Fingerprint: 8975 A9B3 3AA3 7910 385C  5308 ADEF 7684 8031 6BDA

Attachment: signature.asc
Description: PGP signature

Reply via email to