0

I bought a Bluetooth keyboard from China. The manufacturer only has apps for Android and iOS that will allow me to control backlight on the keyboard. So I am currently creating a UWP app for Windows 10 that will allow me to control the backlight.

The Android app creates a (custom?) CRC16 checksum, I am hoping if anyone can help me identify the polynomial and type of CRC16 algorithm it uses. I have tried porting the code to C#, but it seems that the checksums do not match the ones created by the App.

Code:

package com.obins.anne.utils;

import android.support.v4.internal.view.SupportMenu;
import android.support.v4.media.TransportMediator;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;

public class CRC16 {
static byte[] crc16_tab_h;
static byte[] crc16_tab_l;

static {
    byte[] bArr = new byte[AccessibilityNodeInfoCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY];
    bArr[1] = (byte) -63;
    bArr[2] = (byte) -127;
    bArr[3] = (byte) 64;
    bArr[4] = (byte) 1;
    bArr[5] = (byte) -64;
    bArr[6] = Byte.MIN_VALUE;
    bArr[7] = (byte) 65;
    bArr[8] = (byte) 1;
    bArr[9] = (byte) -64;
    bArr[10] = Byte.MIN_VALUE;
    bArr[11] = (byte) 65;
    bArr[13] = (byte) -63;
    bArr[14] = (byte) -127;
    bArr[15] = (byte) 64;
    bArr[16] = (byte) 1;
    bArr[17] = (byte) -64;
    bArr[18] = Byte.MIN_VALUE;
    bArr[19] = (byte) 65;
    bArr[21] = (byte) -63;
    bArr[22] = (byte) -127;
    bArr[23] = (byte) 64;
    bArr[25] = (byte) -63;
    bArr[26] = (byte) -127;
    bArr[27] = (byte) 64;
    bArr[28] = (byte) 1;
    bArr[29] = (byte) -64;
    bArr[30] = Byte.MIN_VALUE;
    bArr[31] = (byte) 65;
    bArr[32] = (byte) 1;
    bArr[33] = (byte) -64;
    bArr[34] = Byte.MIN_VALUE;
    bArr[35] = (byte) 65;
    bArr[37] = (byte) -63;
    bArr[38] = (byte) -127;
    bArr[39] = (byte) 64;
    bArr[41] = (byte) -63;
    bArr[42] = (byte) -127;
    bArr[43] = (byte) 64;
    bArr[44] = (byte) 1;
    bArr[45] = (byte) -64;
    bArr[46] = Byte.MIN_VALUE;
    bArr[47] = (byte) 65;
    bArr[49] = (byte) -63;
    bArr[50] = (byte) -127;
    bArr[51] = (byte) 64;
    bArr[52] = (byte) 1;
    bArr[53] = (byte) -64;
    bArr[54] = Byte.MIN_VALUE;
    bArr[55] = (byte) 65;
    bArr[56] = (byte) 1;
    bArr[57] = (byte) -64;
    bArr[58] = Byte.MIN_VALUE;
    bArr[59] = (byte) 65;
    bArr[61] = (byte) -63;
    bArr[62] = (byte) -127;
    bArr[63] = (byte) 64;
    bArr[64] = (byte) 1;
    bArr[65] = (byte) -64;
    bArr[66] = Byte.MIN_VALUE;
    bArr[67] = (byte) 65;
    bArr[69] = (byte) -63;
    bArr[70] = (byte) -127;
    bArr[71] = (byte) 64;
    bArr[73] = (byte) -63;
    bArr[74] = (byte) -127;
    bArr[75] = (byte) 64;
    bArr[76] = (byte) 1;
    bArr[77] = (byte) -64;
    bArr[78] = Byte.MIN_VALUE;
    bArr[79] = (byte) 65;
    bArr[81] = (byte) -63;
    bArr[82] = (byte) -127;
    bArr[83] = (byte) 64;
    bArr[84] = (byte) 1;
    bArr[85] = (byte) -64;
    bArr[86] = Byte.MIN_VALUE;
    bArr[87] = (byte) 65;
    bArr[88] = (byte) 1;
    bArr[89] = (byte) -64;
    bArr[90] = Byte.MIN_VALUE;
    bArr[91] = (byte) 65;
    bArr[93] = (byte) -63;
    bArr[94] = (byte) -127;
    bArr[95] = (byte) 64;
    bArr[97] = (byte) -63;
    bArr[98] = (byte) -127;
    bArr[99] = (byte) 64;
    bArr[100] = (byte) 1;
    bArr[101] = (byte) -64;
    bArr[102] = Byte.MIN_VALUE;
    bArr[103] = (byte) 65;
    bArr[104] = (byte) 1;
    bArr[105] = (byte) -64;
    bArr[106] = Byte.MIN_VALUE;
    bArr[107] = (byte) 65;
    bArr[109] = (byte) -63;
    bArr[110] = (byte) -127;
    bArr[111] = (byte) 64;
    bArr[112] = (byte) 1;
    bArr[113] = (byte) -64;
    bArr[114] = Byte.MIN_VALUE;
    bArr[115] = (byte) 65;
    bArr[117] = (byte) -63;
    bArr[118] = (byte) -127;
    bArr[119] = (byte) 64;
    bArr[121] = (byte) -63;
    bArr[122] = (byte) -127;
    bArr[123] = (byte) 64;
    bArr[124] = (byte) 1;
    bArr[125] = (byte) -64;
    bArr[TransportMediator.KEYCODE_MEDIA_PLAY] = Byte.MIN_VALUE;
    bArr[TransportMediator.KEYCODE_MEDIA_PAUSE] = (byte) 65;
    bArr[TransportMediator.FLAG_KEY_MEDIA_NEXT] = (byte) 1;
    bArr[Msgprotocol.SYSTEM_ACK_GET_ID] = (byte) -64;
    bArr[TransportMediator.KEYCODE_MEDIA_RECORD] = Byte.MIN_VALUE;
    bArr[Msgprotocol.SYSTEM_ACK_ENTER_DFU] = (byte) 65;
    bArr[Msgprotocol.SYSTEM_ACK_GET_FW_VER] = (byte) -63;
    bArr[Msgprotocol.SYSTEM_ACK_GET_DEVICE_TYPE] = (byte) -127;
    bArr[Msgprotocol.SYSTEM_ACK_GET_PROTOCOL_VER] = (byte) 64;
    bArr[Msgprotocol.SYSTEM_ACK_SET_SYNC_CODE] = (byte) -63;
    bArr[Msgprotocol.LEDSTYLE_ACK_MODE_GET_USER_STATIC_CRC_ID] = (byte) -127;
    bArr[Msgprotocol.BLE_ACK_CURRENT_HOST_QUERY] = (byte) 64;
    bArr[Msgprotocol.BLE_ACK_COMP_MODE] = (byte) 1;
    bArr[141] = (byte) -64;
    bArr[142] = Byte.MIN_VALUE;
    bArr[143] = (byte) 65;
    bArr[145] = (byte) -63;
    bArr[146] = (byte) -127;
    bArr[147] = (byte) 64;
    bArr[148] = (byte) 1;
    bArr[149] = (byte) -64;
    bArr[150] = Byte.MIN_VALUE;
    bArr[151] = (byte) 65;
    bArr[152] = (byte) 1;
    bArr[153] = (byte) -64;
    bArr[154] = Byte.MIN_VALUE;
    bArr[155] = (byte) 65;
    bArr[157] = (byte) -63;
    bArr[158] = (byte) -127;
    bArr[159] = (byte) 64;
    bArr[161] = (byte) -63;
    bArr[162] = (byte) -127;
    bArr[163] = (byte) 64;
    bArr[164] = (byte) 1;
    bArr[165] = (byte) -64;
    bArr[166] = Byte.MIN_VALUE;
    bArr[167] = (byte) 65;
    bArr[168] = (byte) 1;
    bArr[169] = (byte) -64;
    bArr[170] = Byte.MIN_VALUE;
    bArr[171] = (byte) 65;
    bArr[173] = (byte) -63;
    bArr[174] = (byte) -127;
    bArr[175] = (byte) 64;
    bArr[176] = (byte) 1;
    bArr[177] = (byte) -64;
    bArr[178] = Byte.MIN_VALUE;
    bArr[179] = (byte) 65;
    bArr[181] = (byte) -63;
    bArr[182] = (byte) -127;
    bArr[183] = (byte) 64;
    bArr[185] = (byte) -63;
    bArr[186] = (byte) -127;
    bArr[187] = (byte) 64;
    bArr[188] = (byte) 1;
    bArr[189] = (byte) -64;
    bArr[190] = Byte.MIN_VALUE;
    bArr[191] = (byte) 65;
    bArr[193] = (byte) -63;
    bArr[194] = (byte) -127;
    bArr[195] = (byte) 64;
    bArr[196] = (byte) 1;
    bArr[197] = (byte) -64;
    bArr[198] = Byte.MIN_VALUE;
    bArr[199] = (byte) 65;
    bArr[200] = (byte) 1;
    bArr[201] = (byte) -64;
    bArr[202] = Byte.MIN_VALUE;
    bArr[203] = (byte) 65;
    bArr[205] = (byte) -63;
    bArr[206] = (byte) -127;
    bArr[207] = (byte) 64;
    bArr[208] = (byte) 1;
    bArr[209] = (byte) -64;
    bArr[210] = Byte.MIN_VALUE;
    bArr[211] = (byte) 65;
    bArr[213] = (byte) -63;
    bArr[214] = (byte) -127;
    bArr[215] = (byte) 64;
    bArr[217] = (byte) -63;
    bArr[218] = (byte) -127;
    bArr[219] = (byte) 64;
    bArr[220] = (byte) 1;
    bArr[221] = (byte) -64;
    bArr[222] = Byte.MIN_VALUE;
    bArr[223] = (byte) 65;
    bArr[224] = (byte) 1;
    bArr[225] = (byte) -64;
    bArr[226] = Byte.MIN_VALUE;
    bArr[227] = (byte) 65;
    bArr[229] = (byte) -63;
    bArr[230] = (byte) -127;
    bArr[231] = (byte) 64;
    bArr[233] = (byte) -63;
    bArr[234] = (byte) -127;
    bArr[235] = (byte) 64;
    bArr[236] = (byte) 1;
    bArr[237] = (byte) -64;
    bArr[238] = Byte.MIN_VALUE;
    bArr[239] = (byte) 65;
    bArr[241] = (byte) -63;
    bArr[242] = (byte) -127;
    bArr[243] = (byte) 64;
    bArr[244] = (byte) 1;
    bArr[245] = (byte) -64;
    bArr[246] = Byte.MIN_VALUE;
    bArr[247] = (byte) 65;
    bArr[248] = (byte) 1;
    bArr[249] = (byte) -64;
    bArr[250] = Byte.MIN_VALUE;
    bArr[251] = (byte) 65;
    bArr[253] = (byte) -63;
    bArr[254] = (byte) -127;
    bArr[MotionEventCompat.ACTION_MASK] = (byte) 64;
    crc16_tab_h = bArr;
    bArr = new byte[AccessibilityNodeInfoCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY];
    bArr[1] = (byte) -64;
    bArr[2] = (byte) -63;
    bArr[3] = (byte) 1;
    bArr[4] = (byte) -61;
    bArr[5] = (byte) 3;
    bArr[6] = (byte) 2;
    bArr[7] = (byte) -62;
    bArr[8] = (byte) -58;
    bArr[9] = (byte) 6;
    bArr[10] = (byte) 7;
    bArr[11] = (byte) -57;
    bArr[12] = (byte) 5;
    bArr[13] = (byte) -59;
    bArr[14] = (byte) -60;
    bArr[15] = (byte) 4;
    bArr[16] = (byte) -52;
    bArr[17] = (byte) 12;
    bArr[18] = (byte) 13;
    bArr[19] = (byte) -51;
    bArr[20] = (byte) 15;
    bArr[21] = (byte) -49;
    bArr[22] = (byte) -50;
    bArr[23] = (byte) 14;
    bArr[24] = (byte) 10;
    bArr[25] = (byte) -54;
    bArr[26] = (byte) -53;
    bArr[27] = (byte) 11;
    bArr[28] = (byte) -55;
    bArr[29] = (byte) 9;
    bArr[30] = (byte) 8;
    bArr[31] = (byte) -56;
    bArr[32] = (byte) -40;
    bArr[33] = (byte) 24;
    bArr[34] = (byte) 25;
    bArr[35] = (byte) -39;
    bArr[36] = (byte) 27;
    bArr[37] = (byte) -37;
    bArr[38] = (byte) -38;
    bArr[39] = (byte) 26;
    bArr[40] = (byte) 30;
    bArr[41] = (byte) -34;
    bArr[42] = (byte) -33;
    bArr[43] = (byte) 31;
    bArr[44] = (byte) -35;
    bArr[45] = (byte) 29;
    bArr[46] = (byte) 28;
    bArr[47] = (byte) -36;
    bArr[48] = (byte) 20;
    bArr[49] = (byte) -44;
    bArr[50] = (byte) -43;
    bArr[51] = (byte) 21;
    bArr[52] = (byte) -41;
    bArr[53] = (byte) 23;
    bArr[54] = (byte) 22;
    bArr[55] = (byte) -42;
    bArr[56] = (byte) -46;
    bArr[57] = (byte) 18;
    bArr[58] = (byte) 19;
    bArr[59] = (byte) -45;
    bArr[60] = (byte) 17;
    bArr[61] = (byte) -47;
    bArr[62] = (byte) -48;
    bArr[63] = (byte) 16;
    bArr[64] = (byte) -16;
    bArr[65] = (byte) 48;
    bArr[66] = (byte) 49;
    bArr[67] = (byte) -15;
    bArr[68] = (byte) 51;
    bArr[69] = (byte) -13;
    bArr[70] = (byte) -14;
    bArr[71] = (byte) 50;
    bArr[72] = (byte) 54;
    bArr[73] = (byte) -10;
    bArr[74] = (byte) -9;
    bArr[75] = (byte) 55;
    bArr[76] = (byte) -11;
    bArr[77] = (byte) 53;
    bArr[78] = (byte) 52;
    bArr[79] = (byte) -12;
    bArr[80] = (byte) 60;
    bArr[81] = (byte) -4;
    bArr[82] = (byte) -3;
    bArr[83] = (byte) 61;
    bArr[84] = (byte) -1;
    bArr[85] = (byte) 63;
    bArr[86] = (byte) 62;
    bArr[87] = (byte) -2;
    bArr[88] = (byte) -6;
    bArr[89] = (byte) 58;
    bArr[90] = (byte) 59;
    bArr[91] = (byte) -5;
    bArr[92] = (byte) 57;
    bArr[93] = (byte) -7;
    bArr[94] = (byte) -8;
    bArr[95] = (byte) 56;
    bArr[96] = (byte) 40;
    bArr[97] = (byte) -24;
    bArr[98] = (byte) -23;
    bArr[99] = (byte) 41;
    bArr[100] = (byte) -21;
    bArr[101] = (byte) 43;
    bArr[102] = (byte) 42;
    bArr[103] = (byte) -22;
    bArr[104] = (byte) -18;
    bArr[105] = (byte) 46;
    bArr[106] = (byte) 47;
    bArr[107] = (byte) -17;
    bArr[108] = (byte) 45;
    bArr[109] = (byte) -19;
    bArr[110] = (byte) -20;
    bArr[111] = (byte) 44;
    bArr[112] = (byte) -28;
    bArr[113] = (byte) 36;
    bArr[114] = (byte) 37;
    bArr[115] = (byte) -27;
    bArr[116] = (byte) 39;
    bArr[117] = (byte) -25;
    bArr[118] = (byte) -26;
    bArr[119] = (byte) 38;
    bArr[120] = (byte) 34;
    bArr[121] = (byte) -30;
    bArr[122] = (byte) -29;
    bArr[123] = (byte) 35;
    bArr[124] = (byte) -31;
    bArr[125] = (byte) 33;
    bArr[TransportMediator.KEYCODE_MEDIA_PLAY] = (byte) 32;
    bArr[TransportMediator.KEYCODE_MEDIA_PAUSE] = (byte) -32;
    bArr[TransportMediator.FLAG_KEY_MEDIA_NEXT] = (byte) -96;
    bArr[Msgprotocol.SYSTEM_ACK_GET_ID] = (byte) 96;
    bArr[TransportMediator.KEYCODE_MEDIA_RECORD] = (byte) 97;
    bArr[Msgprotocol.SYSTEM_ACK_ENTER_DFU] = (byte) -95;
    bArr[Msgprotocol.SYSTEM_ACK_PING] = (byte) 99;
    bArr[Msgprotocol.SYSTEM_ACK_GET_FW_VER] = (byte) -93;
    bArr[Msgprotocol.SYSTEM_ACK_GET_DEVICE_TYPE] = (byte) -94;
    bArr[Msgprotocol.SYSTEM_ACK_GET_PROTOCOL_VER] = (byte) 98;
    bArr[Msgprotocol.SYSTEM_ACK_IS_SYNC_CODE] = (byte) 102;
    bArr[Msgprotocol.SYSTEM_ACK_SET_SYNC_CODE] = (byte) -90;
    bArr[Msgprotocol.LEDSTYLE_ACK_MODE_GET_USER_STATIC_CRC_ID] = (byte) -89;
    bArr[Msgprotocol.BLE_ACK_CURRENT_HOST_QUERY] = (byte) 103;
    bArr[Msgprotocol.BLE_ACK_COMP_MODE] = (byte) -91;
    bArr[141] = (byte) 101;
    bArr[142] = (byte) 100;
    bArr[143] = (byte) -92;
    bArr[144] = (byte) 108;
    bArr[145] = (byte) -84;
    bArr[146] = (byte) -83;
    bArr[147] = (byte) 109;
    bArr[148] = (byte) -81;
    bArr[149] = (byte) 111;
    bArr[150] = (byte) 110;
    bArr[151] = (byte) -82;
    bArr[152] = (byte) -86;
    bArr[153] = (byte) 106;
    bArr[154] = (byte) 107;
    bArr[155] = (byte) -85;
    bArr[156] = (byte) 105;
    bArr[157] = (byte) -87;
    bArr[158] = (byte) -88;
    bArr[159] = (byte) 104;
    bArr[160] = (byte) 120;
    bArr[161] = (byte) -72;
    bArr[162] = (byte) -71;
    bArr[163] = (byte) 121;
    bArr[164] = (byte) -69;
    bArr[165] = (byte) 123;
    bArr[166] = (byte) 122;
    bArr[167] = (byte) -70;
    bArr[168] = (byte) -66;
    bArr[169] = (byte) 126;
    bArr[170] = Byte.MAX_VALUE;
    bArr[171] = (byte) -65;
    bArr[172] = (byte) 125;
    bArr[173] = (byte) -67;
    bArr[174] = (byte) -68;
    bArr[175] = (byte) 124;
    bArr[176] = (byte) -76;
    bArr[177] = (byte) 116;
    bArr[178] = (byte) 117;
    bArr[179] = (byte) -75;
    bArr[180] = (byte) 119;
    bArr[181] = (byte) -73;
    bArr[182] = (byte) -74;
    bArr[183] = (byte) 118;
    bArr[184] = (byte) 114;
    bArr[185] = (byte) -78;
    bArr[186] = (byte) -77;
    bArr[187] = (byte) 115;
    bArr[188] = (byte) -79;
    bArr[189] = (byte) 113;
    bArr[190] = (byte) 112;
    bArr[191] = (byte) -80;
    bArr[192] = (byte) 80;
    bArr[193] = (byte) -112;
    bArr[194] = (byte) -111;
    bArr[195] = (byte) 81;
    bArr[196] = (byte) -109;
    bArr[197] = (byte) 83;
    bArr[198] = (byte) 82;
    bArr[199] = (byte) -110;
    bArr[200] = (byte) -106;
    bArr[201] = (byte) 86;
    bArr[202] = (byte) 87;
    bArr[203] = (byte) -105;
    bArr[204] = (byte) 85;
    bArr[205] = (byte) -107;
    bArr[206] = (byte) -108;
    bArr[207] = (byte) 84;
    bArr[208] = (byte) -100;
    bArr[209] = (byte) 92;
    bArr[210] = (byte) 93;
    bArr[211] = (byte) -99;
    bArr[212] = (byte) 95;
    bArr[213] = (byte) -97;
    bArr[214] = (byte) -98;
    bArr[215] = (byte) 94;
    bArr[216] = (byte) 90;
    bArr[217] = (byte) -102;
    bArr[218] = (byte) -101;
    bArr[219] = (byte) 91;
    bArr[220] = (byte) -103;
    bArr[221] = (byte) 89;
    bArr[222] = (byte) 88;
    bArr[223] = (byte) -104;
    bArr[224] = (byte) -120;
    bArr[225] = (byte) 72;
    bArr[226] = (byte) 73;
    bArr[227] = (byte) -119;
    bArr[228] = (byte) 75;
    bArr[229] = (byte) -117;
    bArr[230] = (byte) -118;
    bArr[231] = (byte) 74;
    bArr[232] = (byte) 78;
    bArr[233] = (byte) -114;
    bArr[234] = (byte) -113;
    bArr[235] = (byte) 79;
    bArr[236] = (byte) -115;
    bArr[237] = (byte) 77;
    bArr[238] = (byte) 76;
    bArr[239] = (byte) -116;
    bArr[240] = (byte) 68;
    bArr[241] = (byte) -124;
    bArr[242] = (byte) -123;
    bArr[243] = (byte) 69;
    bArr[244] = (byte) -121;
    bArr[245] = (byte) 71;
    bArr[246] = (byte) 70;
    bArr[247] = (byte) -122;
    bArr[248] = (byte) -126;
    bArr[249] = (byte) 66;
    bArr[250] = (byte) 67;
    bArr[251] = (byte) -125;
    bArr[252] = (byte) 65;
    bArr[253] = (byte) -127;
    bArr[254] = Byte.MIN_VALUE;
    bArr[MotionEventCompat.ACTION_MASK] = (byte) 64;
    crc16_tab_l = bArr;
}

public static int calcCrc16(byte[] data) {
    return calcCrc16(data, 0, data.length);
}

public static int calcCrc16(byte[] data, int offset, int len) {
    return calcCrc16(data, offset, len, SupportMenu.USER_MASK);
}

public static int calcCrc16(byte[] data, int offset, int len, int preval) {
    int ucCRCHi = (MotionEventCompat.ACTION_POINTER_INDEX_MASK & preval) >> 8;
    int ucCRCLo = preval & MotionEventCompat.ACTION_MASK;
    for (int i = 0; i < len; i++) {
        int iIndex = (data[offset + i] ^ ucCRCLo) & MotionEventCompat.ACTION_MASK;
        ucCRCLo = ucCRCHi ^ crc16_tab_h[iIndex];
        ucCRCHi = crc16_tab_l[iIndex];
    }
    return ((ucCRCHi & MotionEventCompat.ACTION_MASK) << 8) | ((ucCRCLo & MotionEventCompat.ACTION_MASK) & SupportMenu.USER_MASK);
}
  • This decompiled code is somewhat difficult to read because constants have been introduced where they don't belong. The decompiler tried to be smart ;-( Otherwise, it is a typical optimized implementation of a CRC16 algorithm. The polynomial was used in computing the two byte arrays, you don't see it any more directly in the code. – Henry Jul 20 '16 at 16:06
  • I got the constants mapped to: http://www.hastebin.com/ridiqavuto.cs (in C#). I aplogise for the offsite link, the code is too big to fit inside a comment. – user3452296 Jul 20 '16 at 16:07
  • I know, the "decompiler" referred to the program not you. – Henry Jul 20 '16 at 16:09
  • Moreover, by typical do you mean the standard, https://stackoverflow.com/questions/22860356/how-to-generate-a-crc-16-from-c-sharp ? Thanks for the help so far! – user3452296 Jul 20 '16 at 16:10
  • Which standard? This question shows 7 different CRC16 algorithms. The differences are typically the init value, the polynomial, byte swapping of the result and bit swapping of the result. This gives a lot of possible combinations, all somewhat "standard". – Henry Jul 20 '16 at 16:12
  • After a bit of searching, I found the table they are using in a much more prettier format here, http://code.taobao.org/p/tm_system/diff/22/trunk/TM/src/com/tm – user3452296 Jul 20 '16 at 16:15
  • That's indeed a much clearer formulation. Can't you just port that one? – Henry Jul 20 '16 at 16:20
  • Yep, that is what I intend do now. I didn't realise that a simple Google search on the method signature would work wonders. Thanks for the help! – user3452296 Jul 20 '16 at 16:23

0 Answers0