首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用JS实现CRC8校验和

用JS实现CRC8校验和
EN

Stack Overflow用户
提问于 2020-05-23 20:40:10
回答 2查看 2.3K关注 0票数 0

已经尝试过CRC8,但我无法得到正确的校验和。

有人知道如何使用JS生成这个校验和吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-24 19:10:21

事实证明这是一个非常棘手的问题,但我认为我有一个解决办法。它是Java的一个JavaScript端口(主要是)。我对代码做了一些简化,以消除那些似乎不影响答案的东西。

首先,我必须在您的Java程序中导出相当于CRC8_DATA的十六进制。我只使用一个简单的bytesToHex例程实现了这个目标,我找到了这里 (这个部分是用这里编写的):

代码语言:javascript
复制
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);
}

一旦我有了这个表,我就把Java代码转换成JavaScript,得到以下结果:

代码语言:javascript
复制
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');

最初的Java是以i=1开头的,因此它实际上不包括校验和计算中的第一个字节。这可能是许多JavaScript库没有给出相同答案的原因之一。

我回去把它和这个在线CRC计算器做了比较。在消除第一个字节(0x02)时,我能够使用CRC-8/MAXIM;DOW-CRC获得等效的结果。

我无法让原来的小提琴工作,即使在删除第一个字节,并改变多项式,以匹配从那个网站的一个。其他一些选择也必须不同。

票数 1
EN

Stack Overflow用户

发布于 2020-05-23 20:47:25

在JavaScript中进行校验和计算在默认情况下数字是双浮点数的语言中进行整数位运算是相当困难的。您的代码必须确保一个数字保持整数,甚至可能保持无符号,并且在特定的位范围内(16位,32位)。这些额外的步骤可能会使事情复杂化。

一些技巧,以确保一个数字是一个x位整数,是通过使用和运算符的位掩码,允许该范围内的所有位。例如,可以通过数字&= 0 0xffff来确保16位数字;此外,我还使用了一些操作,比如num \0或num >>> 0,以确保它是一个32位整数,有符号或无符号。这是防止产生负面结果所必需的,当您在十六进制中显示校验和时,这一点特别奇怪。

显然,我并没有尝试这样做一个快速校验和引擎,我只是想在我的SmallPRNG和艾萨克CPRNG笔(post pending;)之后测试按位计算的可能性。这些算法在所有浏览器和浏览器版本中的执行情况都会有所不同,甚至在某些浏览器版本中可能会非常慢。我相信Chrome会非常快地处理数据,并且校验和可以以合理的速度计算!

基类我将实现多个校验和算法,因此我将创建一个基类,它将为所选算法构造一个状态(ctx)。此状态将跟踪校验和和以及算法类的实例。这个类还将正确处理字符串,同时考虑到它们的编码。

该类还包含对Uint8Array支持的测试。我不确定这是否是测试支持的最佳方法,但它成功了。

代码语言:javascript
复制
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;
    }
}());

现在我们可以用Checksum.registerChecksum添加算法了。每个算法类都应该实现用于处理数据的单个和数组方法,以及在构造校验和对象时调用的设置方法。

BSD16 --这是一个非常简单的算法,这个算法只需要一点点代码。BSD校验和算法!

代码语言:javascript
复制
(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和FNV-1)

另一个简单的算法,FNV哈希算法-它生成32位校验和!

代码语言:javascript
复制
(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);
}());

您可以使用此url阅读全文。

blRfzAsyen4Jc-7bWN0cvNlKPQzViAxIR68edJx4gYcFIOrJiu-kQmmMQJMcHuwZFuvWCqAYLQEPX63ttncdhJUEXU8ThjhPhiHNPwX4FjzI1PxLRMH8Hoj1GlIur1DyZDxwz-4t64Pwqg

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61978309

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档