0

Already tried CRC8 but I wasn't able to get the correct checksum.

Does anyone have an idea of how this checksum could be generated using JS ?

jpaugh
  • 6,634
  • 4
  • 38
  • 90
bdo334
  • 380
  • 2
  • 9
  • 20
  • [This](https://github.com/mode80/crc8js/blob/master/crc8.js) might be a good place to start. Found it by google search for "js crc8." There also appear to be many other NPM packages and github repos out there. – David784 May 23 '20 at 20:44
  • 1
    It would be very considerate of you to include information like that in your question. Otherwise nobody will know what you've tried. Perhaps you could read [this](https://stackoverflow.com/help/how-to-ask) and [this](https://stackoverflow.com/help/minimal-reproducible-example), and then edit your question accordingly? Personally I'd be much more likely to spend time on your problem if I saw the code you tried, with an explanation saying "this is the answer I expected but this is the answer I got." – David784 May 23 '20 at 21:40
  • 1
    I noticed a couple of things about your example code: you've got hex strings, so I suspect you want to end up with `[0x02, 0xfd, 0x10, ...]`. That's not what you get by using `charCodeAt`. Also there are several variables in how CRC8 is calculated: polynomial, init, reflection (in/out), xorout, etc. A couple of resources: https://en.wikipedia.org/wiki/Cyclic_redundancy_check and http://crc.drque.net/ Even with all this I can't find a way to match your checksums...if you can find code in any language (java, c, python) that gives the right results, that might help... – David784 May 23 '20 at 23:25
  • I took a quick look at the Java code, looks like it wouldn't be too hard to port to JavaScript...except your CRC table has constants I can't find. I set up a java project and added dependencies to `org.bouncycastle` and `com.google.guava`...but there are ten constants not defined in the standard google guava. All the ones `Ascii.fXXXX`. If I don't have all the values for that CRC table, not much I can do. If you can give me the correct maven dependency or if you can give me a list of those ten constants and their values, maybe I can take another look. – David784 May 24 '20 at 14:38
  • Does this answer your question? [Generate a Hash from string in Javascript](https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript) – jpaugh Dec 03 '20 at 17:45

2 Answers2

1

This proved to be a very tricky one to solve, but I think I have a solution. It's a JavaScript port (mostly) of the Java. I did some simplifying of the code to eliminate the things that didn't seem to affect the answer.

First I had to export the hex equivalent of the CRC8_DATA in your Java program. I achieved this using just a simple bytesToHex routine I found here (this part is in Java):

System.out.print(bytesToHex(CRC8_DATA));
...
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for (int j = 0; j < bytes.length; j++) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = HEX_ARRAY[v >>> 4];
        hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
    }
    return new String(hexChars);
}

Once I had this table, I just converted the Java code into JavaScript, to arrive at this:

var CRC8_DATA = '005EBCE2613FDD83C29C7E20A3FD1F419DC3217FFCA2401E5F01E3BD3E6082DC237D9FC1421CFEA0E1BF5D0380DE3C62BEE0025CDF81633D7C22C09E1D43A1FF4618FAA427799BC584DA3866E5BB5907DB856739BAE406581947A5FB7826C49A653BD987045AB8E6A7F91B45C6987A24F8A6441A99C7257B3A6486D85B05E7B98CD2306EEDB3510F4E10F2AC2F7193CD114FADF3702ECC92D38D6F31B2EC0E50AFF1134DCE90722C6D33D18F0C52B0EE326C8ED0530DEFB1F0AE4C1291CF2D73CA947628ABF517490856B4EA6937D58B5709EBB536688AD495CB2977F4AA4816E9B7550B88D6346A2B7597C94A14F6A8742AC896154BA9F7B6E80A54D7896B35';

function strToArr(str) {
  var arr = str.match(/[0-9a-f]{2}/ig); // convert into array of hex pairs
  arr = arr.map(x=> parseInt(x, 16)); // convert hex pairs into ints (bytes)
  return arr;
}

CRC8_DATA = strToArr(CRC8_DATA);

function calculateCRC8(bArr) {
  var i = 1;
  var i2 = bArr.length - 1;
  var b = 0;
  while (i <= i2) {
    b = CRC8_DATA[(b ^ bArr[i]) & 255];
    i++;
  }
  return b;
}

function calcFromString(str) {
  // convert from string to "byte" array
  var byte_array = strToArr(str);
  var checksum = calculateCRC8(byte_array)
  console.log(str, checksum.toString(16));
}

calcFromString('02FD 1000 2322 4978 0140 00AF 6000 0000 0000');
calcFromString('02FD 1000 D82E 4F76 0189 00AF FA14 0000 0000');

The original Java is starting with i=1, so it's actually not including the first byte in the checksum calculation. That's probably one of the reasons why a lot of the JavaScript libraries weren't giving the same answer.

I went back and compared this with this online CRC calculator. When eliminating the first byte (0x02), I was able to get equivalent results using CRC-8/MAXIM;DOW-CRC.

I was not able to get the original fiddle working though, even after dropping the first byte and changing the polynomial to match the one from that website. Some of the other options must be different as well.

David784
  • 7,031
  • 2
  • 22
  • 29
-2

Checksum calculation in JavaScript It can be quite difficult to do integer bitwise math in a language where numbers are double floating point numbers by default. Your code has to make sure that a number stays an integer, perhaps even stays unsigned and within a specific bit-range (16-bit, 32-bit). These extra steps might complicate things.

Tricks A few tricks to ensure that a number is an x-bit integer, is by using the AND operator with a bitmask that allows all bits for that range. e.g. ensuring a 16-bit number could be done by number &= 0xffff;. Furthermore I use operations such as num | 0 or num >>> 0 to ensure it is a 32-bit integer, signed or unsigned. This is required to prevent negative results to be generated, which is especially weird looking when you display the checksum in hexadecimal.

Speed Obviously I did not try this to make a quick checksum engine, I merely wanted to test the possibility of bitwise calculation more after my SmallPRNG and ISAAC CPRNG pens (post pending ;)). The algorithms will perform differently in all browsers and browser versions and might even be extremely slow in some. I do believe Chrome will handle data very quickly and checksums can be calculated with a reasonable amount of speed!

Base class I'm going to implement multiple checksum algorithms, so I will create a base class which will construct a state (ctx) for the chosen algorithm. This state will keep track of the checksum and an instance of the algorithm class. This class will also handle strings properly, taking their encoding into account.

This class also contains a test for Uint8Array support. I'm not sure if this is the best way to test for support, but it did the trick.

var hasTyped = (function() {
    if(!('Uint8Array' in window)) {
        return false;
    }

    try {
        var a = new window.Uint8Array(10);
        a[0] = 100;
        if(a[0] === 100) {
            return true;
        }
        return false;
    } catch (e) {
        return false;
    }
}());

Algorithm classes Now we can just add algorithms with Checksum.registerChecksum. Each Algorithm class should implement a single and an array method for processing data and optionally a setup method which will be called when the Checksum object is constructed.

BSD16 Here's a very simple one, only a little bit of code is required for this algorithm. The BSD Checksum algorithm!

(function() {
    'use strict';

    if(typeof(window.Checksum) === "undefined") {
        throw "The Checksum class is required for this code.";
    }

    /**
     * Initialize anything you want in the constructor, such as setting up a lookup
     * table of bytes. Make sure to cache your calculations, so they only have to be
     * done once.
     */
    var BSD16 = function BSD16() {
        this.init = 0;
    };

    /**
     * bsd16 for arrays, each value must be numeric and will be bound to 8-bits (Int8Array or Uint8Array works best!)
     * @param   {Array}  a input (8-bit array)
     * @param   {Number} p previous checksum state
     * @returns {Number} new checksum state
     */
    BSD16.prototype.array = function(a, p) {
        var c = p || 0, i = 0, l = a.length;
        for(; i < l; i++) c = (((((c >>> 1) + ((c & 1) << 15)) | 0) + (a[i] & 0xff)) & 0xffff) | 0;
        return c;
    };

    /**
     * bsd16 for a single value, update a checksum with a new byte
     * @param   {Number} b byte (0-255)
     * @param   {Number} p previous checksum state
     * @returns {Number} new checksum state
     */
    BSD16.prototype.single = function(b, p) {
        var c = p || 0;
        return (((((c >>> 1) + ((c & 1) << 15)) | 0) + (b & 0xff)) & 0xffff) | 0;
    };

    Checksum.registerChecksum("bsd16", BSD16);
}());

FNV32 (FNV-0 and FNV-1)

Another easy one, the FNV Hash algorithm - which generates 32-bit checksums!

(function() {
    'use strict';

    if(typeof(window.Checksum) === "undefined") {
        throw "The Checksum class is required for this code.";
    }

    var prime = 0x01000193;

    /**
     * Initialize anything you want in the constructor, such as setting up a lookup
     * table of bytes. Make sure to cache your calculations, so they only have to be
     * done once.
     */
    var FNV32 = function FNV32() {
        this.init = 2166136261; // fnv-1!
    };

    /**
     * The setup method which will be called when new Checksum("fletcher", ...) is called.
     * This method is supposed to initialize the checksum cipher and to recieve parameters
     * from the constructor.
     *
     * @param {Number} mode the FNV32 mode (FNV-1 (defualt) or FNV-0)
     */
    FNV32.prototype.setup = function(mode) {
        if(mode === 0) {
            this.init = 0; // fnv-0.
        }
    };

    FNV32.prototype.array = function(a, p) {
        var len = a.length,
            fnv = p || this.init;

        for(var i = 0; i < len; i++) {
            fnv = (fnv + (((fnv << 1) + (fnv << 4) + (fnv << 7) + (fnv << 8) + (fnv << 24)) >>> 0)) ^ (a[i] & 0xff);
        }

        return fnv >>> 0;
    };

    FNV32.prototype.single = function(b, p) {
        var fnv = p || this.init;
        return ((fnv + (((fnv << 1) + (fnv << 4) + (fnv << 7) + (fnv << 8) + (fnv << 24)) >>> 0)) ^ (b & 0xff)) >>> 0;
    };

    Checksum.registerChecksum("fnv32", FNV32);
}());

You Can Use This url to read full article

https://codepen.io/ImagineProgramming/post/checksum-algorithms-in-javascript-checksum-js-engine?cf_chl_jschl_tk=39bd0de9934c580b6ce33374feddb9c37ee59c20-1590266531-0-AcdpYddIKyEBHAf0tuLzYDLpqpVAYrXmTKfWqF_3OLQVepxEcJq9z0gjYtxrVssDX487qBCful5gnyyFlqtl1fUzzH-lQXJhSZkUquU7GWLTAWAMbH2st22M1Ef6NxBfdHZKL5K0oLWb7gU88-MWOVWW3Ioponmmm7GVfHqSL7bdGcrSZIWjw_U2hKl57DXPw8YO3eWcykQnewEQPVOV7mQV5MlHPf17K-_Doo9NOoOtFJUQGHZyLJL2ANJAiWP98nK6vBZcIyLh69YUbuYFFgYB7uRmzfnb-NKCFLDbRUTBaq0I6Xr_blRfzAsyen4Jc-7bWN0cvNlKPQzViAxIR68edJx4gYcFIOrJiu-kQmmMQJMcHuwZFuvWCqAYLQEPX63ttncdhJUEXU8ThjhPhiHNPwX4FjzI1PxLRMH8Hoj1GlIur1DyZDxwz-4t64Pwqg

Fouad Abdi
  • 39
  • 5