[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
technical clarification request to RFC-1828.
The last thing I feel like doing is stepping into the war over 1828, however I
do have a technical concern with regard to the specification of a compliant
implementation. I apologise for missing the last call on this document, at
the time I was not involved in this area of standards. This is purely a
technical clarification, I make no judgements about the appropriateness of the
protocol.
My issue is entirely based upon what I consider to be an inadequate
specification of the padding of the initial key. To my "trained" implementors
eye, it's not at all clear from the RFC, and in fact, I had to speak to
someone who implemented it correctly at the bake-off who received additional
information from Bill. (read: I looked at the NRL code)
The RFC does not mis-specify the method of padding, merely it specifies it
inadequately. Given that with the additional information, the compliant
implementation became obvious, I would request the that the working group
insure the clarity of future revisions of 1828.
I think some simple pseudo-code would be enough, as long as the "revision" to
the RFC1323 MD5Final routine was *strongly* noted.
Given that the group seems to be in a war about 1828 and other recently
released drafts, now is as good a time as any to nail down some technical
details.
Sigh,
Paul
-----------------------------------------------------------------------------
Details:
My inadequate interpretation of 1828 caused the following code to be written
(the MD5 routines are the canonical ones from 1323):
/*
* md5_rfc1828
*
* User-friendly way to compute keyed MD5 authentication information for
* a chunk of data.
*
* Call it like this:
*
* char hash[MD5_LEN];
* md5_rfc1828(message, msglength, key, strlen(key), hash, sizeof(hash));
*/
#define FILL_LEN 64 /* 512 bit boundaries for fill */
#define MOD_LEN 56 /* pad key to bit 448 modulo 512 */
boolean
md5_rfc1828 (void *data, int datalen,
char *key, int keylen,
uchar *digest, int digestlen)
{
static uchar padding[FILL_LEN] = { 0x80, 0 };
MD5_CTX context;
int padlen;
if (digestlen < MD5_LEN)
return FALSE;
padlen = keylen % FILL_LEN;
padlen = padlen < MOD_LEN ? MOD_LEN - padlen
: (FILL_LEN+MOD_LEN) - padlen;
MD5Init(&context);
MD5Update(&context, key, keylen);
MD5Update(&context, padding, padlen);
MD5Update(&context, data, datalen);
MD5Update(&context, key, keylen);
MD5Final(digest, &context);
return TRUE;
}
whereas the correct implementation would be:
boolean
md5_rfc1828 (void *data, int datalen,
char *key, int keylen,
uchar *digest, int digestlen)
{
MD5_CTX context;
if (digestlen < MD5_LEN)
return FALSE;
MD5Init(&context);
MD5Update(&context, key, keylen);
RFC_1828_MD5Final(NULL, &context); /* do padding according to 1828 */
MD5Update(&context, data, datalen);
MD5Update(&context, key, keylen);
MD5Final(digest, &context);
return TRUE;
}
void
RFC_1828_MD5Final (unsigned char *digest, /* message digest */
MD5_CTX *context) /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode(bits, context->count, 8);
/*
* Pad out to 56 mod 64.
*/
index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update(context, PADDING, padLen);
/* Append length (before padding) */
MD5Update(context, bits, 8);
| if (digest) { /* change to allow RFC1828 padding */
| /* Store state in digest */
| Encode(digest, context->state, 16);
|
| /*
| * Zeroize sensitive information.
| */
| MD5_memset((POINTER) context, 0, sizeof(*context));
| }
}
Follow-Ups: