#!/usr/bin/perl # This script is contributed by Vadim Vygonets to aid in debugging CRAM-MD5 # authentication. It prompts for three data values: a user name, a password, # and the challenge as sent out by an SMTP server. The challenge is a base-64 # string. It should be copied (cut-and-pasted) literally as the third data # item. The output of the program is the base-64 string that is to be returned # as the response to the challenge. Using the example in RFC 2195: # # User: tim # Password: tanstaaftanstaaf # Challenge: PDE4OTYuNjk3MTcwOTUyQHBvc3RvZmZpY2UucmVzdG9uLm1jaS5uZXQ+ # dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw # # The last line is what you you would send back to the server. # Copyright (c) 2002 # Vadim Vygonets . All rights reserved. # Public domain is OK with me. use MIME::Base64; use DIGEST::MD5; # Prompt for values... print "User: "; chop($user = <>); print "Password: "; chop($passwd = <>); print "Challenge: "; chop($chal = <>); # Strip "334" SMTP server response or "+" POP server response. $chal =~ s/^(?:334|\+) //; $context = new Digest::MD5; # If the length of the password is greater than 64, use the MD5 # hash of the password instead (RFC 2104, chapter 2, verse 1). if (length($passwd) > 64) { $context->add($passwd); $passwd = $context->digest(); $context->reset(); } # Turn passwd into array of chars. @passwd = unpack("C*", pack("a64", $passwd)); # XOR passwd with ipad and opad. for ($i = 0; $i < 64; $i++) { $pass_ipad[$i] = $passwd[$i] ^ 0x36; $pass_opad[$i] = $passwd[$i] ^ 0x5C; } # Append challenge to (passwd XOR ipad) and MD5 the result. $context->add(pack("C64", @pass_ipad), decode_base64($chal)); $digest = $context->digest(); $context->reset(); # Append the result to (passwd XOR opad) and MD5 the result. $context->add(pack("C64", @pass_opad), $digest); $digest = $context->digest(); # Print username, whitespace, and hexadecimal representation of # the resulting digest, BASE64-encoded. print encode_base64($user . " " . unpack("H*", $digest)); # End