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 Jensen 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

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

···

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