15

The Google App Script function computeDigest returns a byte array of the signature. How can I get the string representation of the digest?

I have already tried the bin2String() function.

function sign(){     
var signature = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, "thisisteststring")
Logger.log(bin2String(signature));
}


function bin2String(array) {
  var result = "";
  for (var i = 0; i < array.length; i++) {
    result += String.fromCharCode(parseInt(array[i], 2));
  }
  return result;
}

but it puts "" in the Logs

1
  • you need to post what you have tried. Commented Apr 25, 2013 at 14:09

6 Answers 6

28

If we put Logger.log(signature); right after the call to computeDigest(), we get:

[8, 30, -43, 124, -101, 114, -37, 10, 78, -13, -102, 51, 65, -24, -83, 81]

As represented in javascript, the digest includes both positive and negative integers, so we can't simply treat them as ascii characters. The MD5 algorithm, however, should provide us with 8-bit values, in the range 0x00 to 0xFF (255). Those negative values, then, are just a misinterpretation of the high-order bit; taking it to be a sign bit. To correct, we need to add 256 to any negative value.

How to convert decimal to hex in JavaScript? gives us this for retrieving hex characters:

hexString = yourNumber.toString(16);

Putting that together, here's your sign() function, which is also available as a gist:

function sign(message){     
  message = message || "thisisteststring";
  var signature = Utilities.computeDigest(
                       Utilities.DigestAlgorithm.MD5,
                       message,
                       Utilities.Charset.US_ASCII);
  Logger.log(signature);
  var signatureStr = '';
    for (i = 0; i < signature.length; i++) {
      var byte = signature[i];
      if (byte < 0)
        byte += 256;
      var byteStr = byte.toString(16);
      // Ensure we have 2 chars in our byte, pad with 0
      if (byteStr.length == 1) byteStr = '0'+byteStr;
      signatureStr += byteStr;
    }   
  Logger.log(signatureStr);
  return signatureStr;
}

And here's what the logs contain:

[13-04-25 21:46:55:787 EDT] [8, 30, -43, 124, -101, 114, -37, 10, 78, -13, -102, 51, 65, -24, -83, 81]
[13-04-25 21:46:55:788 EDT] 081ed57c9b72db0a4ef39a3341e8ad51

Let's see what we get from this on-line MD5 Hash Generator:

081ed57c9b72db0a4ef39a3341e8ad51

I tried it with a few other strings, and they consistently matched the result from the on-line generator.

Sign up to request clarification or add additional context in comments.

Comments

17

Just in case this is helpful to anyone else, I've put together a more succinct version of Mogsdad's solution:

function md5(str) {
  return Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, str).reduce(function(str,chr){
    chr = (chr < 0 ? chr + 256 : chr).toString(16);
    return str + (chr.length==1?'0':'') + chr;
  },'');
}

Comments

8

One-liner:

Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, "teststring")
  .map(function(b) {return ("0" + (b < 0 && b + 256 || b).toString(16)).substr(-2)})
  .join("")

3 Comments

Can you explain a bit more about how this works? In the interest of educating future readers.
1) "map" takes each byte in array returned by "computeDigest" and performs some transformation on it. 2) "(b < 0 && b + 256 || b)" - && takes precedence over || so it actually looks like this: ( (b < 0 && b + 256) || b ). It says "If b < 0, give b+256, otherwise give b". 3) ".toString(16)" Convert the corrected "b" value to hex string 4) "0" + hex string (in case b is less than 16, e.g. if b is 1 then: "0"+"1" -> "01". In case b is 16 or more we get "010". But we just want two chars so 5) "substr(-2)" take last two chars 6) join together
In fact you don't need conditionals: inputArray.map(function(b) {return ("0"+((b+256)%256).toString(16)).slice(-2)}).join("");
7

Did somebody say succinct? (/fulldecent arrives to party with the drinking hat, including straws, after everyone else already passed out)

Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, "thisisteststring")
  .map(function(chr){return (chr+256).toString(16).slice(-2)})
  .join('')

Comments

3

Here is an easy way to transform a Byte[] into a String.

Found this in the documentation provided by Google here : https://developers.google.com/apps-script/reference/utilities/utilities#base64Decode(String)

Utilities.newBlob(myByteArray).getDataAsString();

Better late than never. (And since this topic still comes first when searching this topic in Goole, this might help some folks).

Comments

-1

From this post:

function string2Bin(str) {
  var result = [];
  for (var i = 0; i < str.length; i++) {
    result.push(str.charCodeAt(i).toString(2));
  }
  return result;
}

1 Comment

well actually it is bin2string. But I have already tried that. and it doesn't work. Try it for yourself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.