0

I'm currently trying to move over some encoding script from Java to NodeJs.

At the moment the current Java script is as follows:

public static final char[] chars = "0123456789abcdef".toCharArray();

public static String sha1Digest(String str) {
    try {
        MessageDigest instance = MessageDigest.getInstance('SHA-1');
        instance.reset();
        instance.update(str.getBytes('UTF-8'));
        return lastEncode(instance.digest());
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}


public static String lastEncode(byte[] bArr) {
    StringBuilder encoded = new StringBuilder(bArr.length * 2);
    for (byte b : bArr) {
        encoded.append(chars[(b >> 4) & 15]);
        encoded.append(chars[b & 15]);
    }
    return encoded.toString();
}

The initial parameter passed to the sha1Digest function is a string that consists of a URL appended with a secret key.

Currently, I'm trying to transfer the code over to NodeJs in which I have this code (for now):

async function sha1Digest(str) {
  try {
    const sha1 = crypto.createHmac("SHA1");
    const hmac = sha1.update(new Buffer(str, 'utf-8'));
    return encoder(hmac.digest());
  } catch (e) {
    console.dir(e);
  }
}

async function lastEncode(bArr) {
    let chars = "0123456789abcdef".split('')
    let sb = '';
    for (b in bArr) {
        sb = sb + (chars[(b >> 4) & 15]);
        sb = sb + (chars[b & 15]);
    }
    return sb;
}

Sadly tho, I have no understanding of what the part in the for loop in lastEncode does. Is anybody able to help me out with this, and also verify that the sha1Digest function seems correct in the NodeJS?

Much appreciated!

Marco Jacobs
  • 57
  • 1
  • 11

1 Answers1

0

lastEncode turns a byte array into hex nibbles. It turns the array: new byte[] {10, 16, (byte) 255} into the string "0a10ff". (0a is hex notation for 10, ff is hex notation for 255, etc - if this sounds like gobbledygook to you, the web has many tutorials on hexadecimal :P).

Your javascript translation messes up because you're joining on ,. More generally, to do that 'bytes to nibbles' operation of before, see this SO answer.

Just test the lastEncode function by itself. Run it in java, then run your javascript port, and ensure the exact same string is produced in both variants. Only then, move on to the hashing part.

NB: To be clear, this protocol is rather idiotic - you can just hash the byte array itself, there is no need to waste a ton of time turning that into hex nibbles (which is always exactly 2x as large as the input) and then hashing that. But, presumably, you can't mess with the protocol at this point. But if you can, change it. It'll be faster, simpler to explain, and less code. Win-win-win.

EDIT: NB: You also are using a different hash algorithm in the javascript side (HMAC-SHA1 is not the same as just SHA1).

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
  • Thanks for your answer! I've made a typo indeed with the join(','). I've removed that, since I needed an array. Still not quite sure how I would replicate the for loop in Nodejs based on the charArray tho haha.. – Marco Jacobs Oct 29 '20 at 14:27
  • forget the 0123456789abcdef part - focus on the testing part - write code in java that runs a whole bunch of hardcoded example strings through `lastEncode` and replicate this in your javascript code, using that linked SO answer as a guide to how to accomplish the task. – rzwitserloot Oct 29 '20 at 14:46
  • You missed that he's using SHA1 in the Java code but HMAC-SHA1 in the JS code. – President James K. Polk Oct 29 '20 at 21:11
  • Good point, number 11. My answer is focussing on the lastEncode stuff, as Marco indicated he was particularly confused about that one. I'll toss in a quick edit. – rzwitserloot Oct 29 '20 at 21:13