1

I have this custom function to calculate MD5 hash, written in Java. I can't change it. I need to translate it to JavaScript to use it on client side. I tried on my own but I can't manage with JavaScript data types (expecially Java char[])... Any help is appreciated, thanks!

// codes array
char[] codes = new char[64];

// initialise
private void initCodes(){
  codes = new char[64];
  codes[0] = '$';
  int count = 0;
  for (char i='0';i<='9';i++){ count++; codes[count] = i; }
  for (char i='A';i<='Z';i++){ count++; codes[count] = i; }
  for (char i='a';i<='z';i++){ count++; codes[count] = i; }
  codes[63] = '£';
}

// custom MD5 algorithm
public String customMD5(String source) {
  initCodes();
  byte[] buf = new byte[source.length()];
  buf = source.getBytes();
  MessageDigest algorithm = null;
  try {
    algorithm = MessageDigest.getInstance("MD5");
  } catch(NoSuchAlgorithmException e){}
  algorithm.reset();
  algorithm.update(buf);
  byte[] digest = algorithm.digest();
  int len = digest.length;
  char[] encrypted = new char[len];
  for (int i=0;i<len;i++)
    encrypted[i] = codes[(int)(Math.floor((double)((digest[i]+128)/4)))];
  return new String(encrypted);
}
bluish
  • 26,356
  • 27
  • 122
  • 180
  • If you type on google: "md5 javascript" there are plenty of existing libs – Mic May 24 '11 at 13:02
  • but probably there is no lib for this *custom* MD5 – bluish May 24 '11 at 13:19
  • The solution is already given, but you should not name this *custom MD5* - it is not a custom MD5 (there is no such thing - if it were custom, it were no MD5), it is only a custom encoding of the MD5. – Paŭlo Ebermann May 24 '11 at 21:08

1 Answers1

3

See this part here:

  MessageDigest algorithm = null;
  try{
     algorithm = MessageDigest.getInstance("MD5");
  }catch(NoSuchAlgorithmException e){}

? That's where that stuff is accessing the MD5 code that's built into the Java runtime. You'll have to come up with your own implementation of MD5 there, which (to put it mildly) will be the tricky part.

All that the posted Java code really does (on top of calling the runtime to do the actual hashing) is to map the resulting hash (part of it, anyway) through a character lookup table.

edit — the lookup table built by that Java code is an array with "$", the digits, the upper-case letters, the lower-case letters, and then (surprisingly) "£". (The last character is surprising because it's not an old-school 7-bit ASCII character code, but whatever.) In JavaScript, that's:

var codes = "$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz£";

The Java code then takes each 8-bit byte produced by the hash algorithm and looks up a code character by adding 128 to the byte and then dividing by 4. Java bytes are treated as signed values, so that has the effect of mapping every byte into the range 0 ... 63. That value is then used as a lookup into the code array.

Thus if you have a JavaScript MD5 facility that can give you back an array of numbers in the range -128 ... 127 (that is, signed 8-bit values), you could translate the result through the code array like this:

var digest = MagicJavaScriptMD5(source);
var result = [];
for (var i = 0; i < digest.length; ++i)
  result.push(codes.charAt(~~((digest[i] + 128) / 4)));
var resultString = result.join('');

EDIT by the OP: I take the liberty of posting here the right solution, that is highly derived from @Pointy's one. It requires md5.js from http://pajhome.org.uk/crypt/md5/.

/* MD5 in byte[] format */
function byteArray_md5(s) {
        var output = [];
        var input = rstr_md5(str2rstr_utf8(s)); //here it uses md5.js
        for(var i = 0; i < input.length; i++)
                output[i] = input.charCodeAt(i);
        return output;
}
/* MD5 with custom mapping.
 * It's a normal MD5 with a final char mapping of the hash.
 */
function md5WithCustomMapping(source) {
    var codes = "$0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz£";
    var digest = byteArray_md5(source);

    var result = [];
    for (var i = 0; i < digest.length; ++i)
        result.push(
                codes.charAt(
                        ~~( ( digest[i] + 128 * (digest[i]<128 ? 1 : -1) )/4 )
                        )
                    );
    return result.join('');
}
bluish
  • 26,356
  • 27
  • 122
  • 180
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • You are right! My problem is: how can I manage an array of char in JavaScript? – bluish May 24 '11 at 13:20
  • A JavaScript string works more-or-less like a Java char array, at least to some extent. Certainly for the purposes of that mapping a JavaScript string should work. I'll update my answer. – Pointy May 24 '11 at 14:07