Base64 and MD5 fun

I’m trying to implement the auth-md5 authentication scheme in the
SyncML spec but have hit a very confusing snag that’s been baking my
noodle.

The digest setup is fairly simple (in theory):
base64(md5(base64(md5(“username:password”) + “:” + nonce)))

Here’s some PHP code I found on the Horde mailing list that makes
this happen:
<?php

function md5_base64($data)
{
	return base64_encode(pack('H*',md5($data)));
}

function md5_syncml_new($user,$pass,$nonce)
{
	return md5_base64(md5_base64($user.":".$pass).":".$nonce);
}

print base64_encode(pack('H*',md5("Bruce2:OhBehave")));
print md5_syncml_new("Bruce2","OhBehave","Nonce");
print "Zz6EivR3yeaaENcRN6lpAQ==";

?>

Works perfectly. The same (at least unless I’m missing something
truly painfully obvious) in Ruby, doesn’t:
def md5_base64(data)
Base64.encode64(MD5.digest(data))
end

def md5_syncml_new(user,pass,nonce)
return md5_base64(md5_base64(user+":"+pass)+":"+nonce);
end

puts md5_syncml_new(“Bruce2”,“OhBehave”,“Nonce”)

which gives: rBVodJ8RrZ3qC7EksecINA==

Things seem to fall apart in the final step of appending the nonce
and hashing it again.

PHP’s md5() and MD5.hexdigest() come out the same
print md5(“Bruce2:OhBehave”);
=> 3ed11dafc941438e486d3d5b64892b39

>> MD5.hexdigest("Bruce2:OhBehave")
=> "3ed11dafc941438e486d3d5b64892b39"

Base64 encoding that also works out (Note, php’s pack() on the md5()
output is equivlalent to MD5.digest()):
print base64_encode(pack(‘H*’,md5(“Bruce2:OhBehave”)));
=> PtEdr8lBQ45IbT1bZIkrOQ==

>> Base64.encode64(MD5.digest("Bruce2:OhBehave"))
=> "PtEdr8lBQ45IbT1bZIkrOQ==\n"

I’m willing to bet there’s something horribly wrong with my code, but
have just been staring at it far too much to see it. Any help would
be hugely appreciated.

Thanks,
-Dane

Dane J. wrote:

Base64 encoding that also works out (Note, php’s pack() on the md5()
output is equivlalent to MD5.digest()):
print base64_encode(pack(‘H*’,md5(“Bruce2:OhBehave”)));
=> PtEdr8lBQ45IbT1bZIkrOQ==

Base64.encode64(MD5.digest(“Bruce2:OhBehave”))
=> “PtEdr8lBQ45IbT1bZIkrOQ==\n”

The clue is right here. The Ruby code appends a “\n”.

This seems to give the result you want (note the “.chomp”)
p md5_base64(md5_base64(“Bruce2:OhBehave”).chomp+":"+“Nonce”)

Vidar

On Dec 11, 2006, at 10:31 PM, Dane J. wrote:

I’m willing to bet there’s something horribly wrong with my code,
but have just been staring at it far too much to see it. Any help
would be hugely appreciated.

Yep. There was. I wish I could claim to have found it, but it was a
friend that came to the rescue.

Ruby’s Base64 appends a newline, while PHP’s does not.

print base64_encode(pack(‘H*’,md5(“Bruce2:OhBehave”)));
=> PtEdr8lBQ45IbT1bZIkrOQ==

vs.

Base64.encode64(MD5.digest(“Bruce2:OhBehave”))
=> “PtEdr8lBQ45IbT1bZIkrOQ==\n”

-Dane