请将CRC16的C语言算法,改造为JAVA语言算法,万分感谢!
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请将CRC16的C语言算法,改造为JAVA语言算法,万分感谢!相关的知识,希望对你有一定的参考价值。
CRC16的C语言算法:
#define PRESET_VALUE 0xFFFF
#define POLYNOMIAL 0x8408
unsigned int uiCrc16Cal(unsigned char const * pucY, unsigned char ucX)
unsignedchar ucI,ucJ;
unsignedshort int uiCrcValue = PRESET_VALUE;
for(ucI = 0; ucI < ucX; ucI++)
uiCrcValue = uiCrcValue ^ *(pucY + ucI);
for(ucJ = 0; ucJ < 8; ucJ++)
if(uiCrcValue& 0x0001)
uiCrcValue= (uiCrcValue >> 1) ^ POLYNOMIAL;
else
uiCrcValue= (uiCrcValue >> 1);
return uiCrcValue;
int CRC;
int i, Temp;
CRC = 0xffff;
for (i = 0; i < Len; i++)
CRC = CRC ^ byteToInteger(Buf[i]);
// System.out.println(byteToInteger(Buf[i]));
for (Temp = 0; Temp < 8; Temp++)
if ((CRC & 0x01) == 1)
CRC = (CRC >> 1) ^ 0xA001;
else
CRC = CRC >> 1;
return CRC;
追问
byteToInteger这个函数哪儿的?我无法引用,谢谢!
追答// 保留低8位,转换成int型
public static int byteToInteger(byte b)
int value;
value = b & 0xff;
return value;
对不起,忘了贴了
用 C 语言在消息的开头使用 CRC 哈希计算 CRC32
【中文标题】用 C 语言在消息的开头使用 CRC 哈希计算 CRC32【英文标题】:CRC32 calculation with CRC hash at the beginning of the message in C 【发布时间】:2015-10-13 15:01:39 【问题描述】:我需要计算消息的 CRC 并将其放在此消息的 开头,以便带有“前置”补丁字节的消息的最终 CRC 等于 0。我能够做到在几篇文章的帮助下,这很容易,但不适用于我的具体参数。问题是我必须使用给定的 CRC32 算法来计算内存块的 CRC,但我没有计算这 4 个补丁字节/“CRC 类型”的“反向”算法。给定的 CRC32 算法的参数是:
多项式:0x04C11DB7 字节序:大字节序 初始值:0xFFFFFFFF 反映:假 异或输出:0L 测试流:0x0123、0x4567、0x89AB、0xCDEF 结果 CRC = 0x612793C3计算CRC的代码(半字节,表驱动,希望数据类型定义不言自明):
uint32 crc32tab(uint16* data, uint32 len, uint32 crc)
uint8 nibble;
int i;
while(len--)
for(i = 3; i >= 0; i--)
nibble = (*data >> i*4) & 0x0F;
crc = ((crc << 4) | nibble) ^ tab[crc >> 28];
data++;
return crc;
所需的表是(我认为短 [16] 表应该包含大 [256] 表中的每 16 个元素,但此表实际上包含 first 16 个元素,但它就是这样提供给我):
static const uint32 tab[16]=
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
;
我修改了代码,使其不再那么长,但功能保持不变。问题是这种正向 CRC 计算看起来更像是反向/反向 CRC 计算。 我花了将近一周的时间试图找出正确的多项式/算法/表格组合,但没有运气。如果有帮助,我想出了与上面的表驱动代码相对应的按位算法,尽管这并不难:
uint32 crc32(uint16* data, uint32 len, uint32 crc)
uint32 i;
while(len--)
for(i = 0; i < 16; i++)
// #define POLY 0x04C11DB7
crc = (crc << 1) ^ (((crc ^ *data) & 0x80000000) ? POLY : 0);
crc ^= *data++;
return crc;
这是预期的结果 - 前 2 个 16 位字生成所需的未知 CRC,其余的是已知数据本身(通过将这些示例提供给提供的算法,结果为 0)。
0x3288, 0xD244, 0xCDEF, 0x89AB, 0x4567, 0x0123
0xC704, 0xDD7B, 0x0000 - append as many zeros as you like, the result is the same
0xCEBD, 0x1ADD, 0xFFFF
0x81AB, 0xB932, 0xFFFF, 0xFFFF
0x0857, 0x0465, 0x0000, 0x0123
0x1583, 0xD959, 0x0123
^ ^
| |
unknown bytes that I need to calculate
我认为在 0xFFFF 或 0x0000 字上进行测试很方便,因为计算方向和字节序并不重要(我希望 :D)。所以要小心使用其他测试字节,因为计算的方向是相当曲折的:D。您还可以看到,通过仅向算法提供零(向前和向后),结果就是所谓的残差 (0xC704DD7B),这可能会有所帮助。
所以...我写了至少 10 个不同的函数(逐位、表格、多项式组合等)试图解决这个问题,但没有运气。我在这里给你我寄希望于的功能。这是上面表格驱动算法的“反转”算法,当然有不同的表格。问题是我从中得到的唯一正确的 CRC 是全 0 消息,这并不出人意料。我还编写了按位算法的反向实现(反向移位等),但是那个只正确返回第一个字节。 这是表驱动的,指向 data 的指针应该指向消息的最后一个元素,而 crc 输入应该是请求的 crc(整个消息为 0 或您也许可以采取另一种方法 - 消息的最后 4 个字节是您正在寻找的 CRC:Calculating CRC initial value instead of appending the CRC to payload) :
uint32 crc32tabrev(uint16* data, uint32 len, uint32 crc)
uint8 nibble;
int i;
while(len--)
for(i = 0; i < 4; i++)
nibble = (*data >> i*4) & 0x0F;
crc = (crc >> 4) ^ revtab[((crc ^ nibble) & 0x0F)];
data--;
return reverse(crc); //reverse() flips all bits around center (MSB <-> LSB ...)
这张桌子,我希望它是“被选中的”:
static const uint32 revtab[16]=
0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC,
0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C,
0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C,
0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C
;
如您所见,这个算法有一些好处,让我在圈子里跑,我想我可能走在正确的轨道上,但我错过了一些东西。我希望多一双眼睛能看到我看不到的东西。我很抱歉这篇长文(没有土豆:D),但我认为所有这些解释都是必要的。提前感谢您的见解或建议。
【问题讨论】:
您的 CRC 计算完全搞砸了。使用来自消息的位和 CRC 的高位的异或来选择表条目。对于您的按位 CRC 例程,您决定是否与POLY
互斥或与^ *data
无关,因此甚至不需要存在!正确的做法是将数据向上移动到CRC的顶部,然后再决定高位。您没有计算您指定的 CRC,顺便说一下,它是 MPEG2 CRC-32。
嗯,你是对的,那些 CRC 的计算是不正确的,但我无法改变这一点,因为原始的 CRC 计算和表格与算法参数一起提供给我,我只需要找到这 4 个补丁字节。如果官方 CRC-32/MPEG-2 算法在我的问题中通过了该测试流,那么我想我是这里错的那个人,但我认为谁制作了那个算法(给我的那个)没有遵循他应该的规格。但是与 *data 的 XOR 是我的错误,真的...原来是 (... & 1),所以我只是将 1 更改为 0x80000000 认为它会有所帮助:D
您应该发布原始的 CRC 计算和表格,没有任何变化。也许原版没问题。
好吧,表格是一样的,计算也是一样的,它分为3个函数,所以我把它们放在一起..但是正如我写的那样,那个短表应该包含大的每16个元素表(至少这是我读到的),但是这个表包含大表的 16 个元素,我认为这是问题
您不应将校验和称为 CRC,因为您计算的不是 CRC。
【参考方案1】:
我将回答您的 CRC 规范,即CRC-32/MPEG-2。我将不得不忽略您计算该 CRC 的尝试,因为它们不正确。
无论如何,为了回答你的问题,我碰巧写了一个程序来解决这个问题。它被称为spoof.c
。它非常快速地计算出消息中要更改的位以获得所需的 CRC。它按 log(n) 时间顺序执行此操作,其中 n 是消息的长度。这是一个例子:
让我们使用九字节消息123456789
(这些数字以 ASCII 表示)。我们将在它前面加上四个零字节,我们将对其进行更改以在最后获得所需的 CRC。十六进制的消息是:00 00 00 00 31 32 33 34 35 36 37 38 39
。现在我们计算该消息的 CRC-32/MPEG-2。我们得到373c5870
。
现在我们使用这个输入运行spoof
,它是 CRC 长度(以位为单位)、未反映的事实、多项式、我们刚刚计算的 CRC、消息的长度(以字节为单位)以及所有 32 位前四个字节中的位置(这是我们允许 spoof
更改的位置):
32 0 04C11DB7
373c5870 13
0 0 1 2 3 4 5 6 7
1 0 1 2 3 4 5 6 7
2 0 1 2 3 4 5 6 7
3 0 1 2 3 4 5 6 7
它给出了这个输出,其中包含前四个字节中要设置的位:
invert these bits in the sequence:
offset bit
0 1
0 2
0 4
0 5
0 6
1 0
1 2
1 5
1 7
2 0
2 2
2 5
2 6
2 7
3 0
3 1
3 2
3 4
3 5
3 7
然后我们将前四个字节设置为:76 a5 e5 b7
。然后我们通过计算消息76 a5 e5 b7 31 32 33 34 35 36 37 38 39
的CRC-32/MPEG-2 进行测试,得到00000000
,即预期的结果。
您可以使spoof.c
适应您的应用程序。
这是一个使用逐位算法正确计算字节流上的 CRC-32/MPEG-2 的示例:
uint32_t crc32m(uint32_t crc, const unsigned char *buf, size_t len)
int k;
while (len--)
crc ^= (uint32_t)(*buf++) << 24;
for (k = 0; k < 8; k++)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
return crc;
并使用问题中的表格使用 nybble-wise 算法(这是正确的):
uint32_t crc_table[] =
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
;
uint32_t crc32m_nyb(uint32_t crc, const unsigned char *buf, size_t len)
while (len--)
crc ^= (uint32_t)(*buf++) << 24;
crc = (crc << 4) ^ crc_table[crc >> 28];
crc = (crc << 4) ^ crc_table[crc >> 28];
return crc;
在这两种情况下,初始 CRC 必须是 0xffffffff
。
【讨论】:
谢谢你的回答,我相信有人会好好利用它,但就我而言,计算CRC的CRC算法有点特殊,它不符合规范(CRC-32 / MPEG-2)它说它确实(至少我认为是这样),上面的答案用蛮力解决了它,但是那个答案被删除了,我不知道为什么而且我也不知道知道是谁首先发布的。但是再次感谢您的回答,它肯定会帮助解决我的问题和遵循规范的 CRC 生成器 :D :)【参考方案2】:好吧,在我提出问题几个小时后,一个我不记得名字的人发布了我的问题的答案,结果证明是正确的。不知何故,这个答案被完全删除了,我不知道为什么或是谁做的,但我要感谢这个人,如果你会看到这个,请再次发布你的答案,我会删除这个。但是对于其他用户来说,这是他对我有用的答案,再次感谢你,神秘的一个(不幸的是,我无法很好地复制他的笔记和建议,只是代码本身):
编辑:最初的答案来自用户samgak,所以这会一直留在这里,直到他发布他的答案。
逆向CRC算法:
uint32 revcrc32(uint16* data, uint32 len, uint32 crc)
uint32 i;
data += len - 1;
while(len--)
crc ^= *data--;
for(i = 0; i < 16; i++)
uint32 crc1 = ((crc ^ POLY) >> 1) | 0x80000000;
uint32 crc2 = crc >> 1;
if(((crc1 << 1) ^ (((crc1 ^ *data) & 0x80000000) ? POLY : 0)) == crc)
crc = crc1;
else if(((crc2 << 1) ^ (((crc2 ^ *data) & 0x80000000) ? POLY : 0)) == crc)
crc = crc2;
return crc;
查找补丁字节:
#define CRC_OF_ZERO 0xb7647d
void bruteforcecrc32(uint32 targetcrc)
// compute prefixes:
uint16 j;
for(j = 0; j <= 0xffff; j++)
uint32 crc = revcrc32(&j, 1, targetcrc);
if((crc >> 16) == (CRC_OF_ZERO >> 16))
printf("prefixes: %04lX %04lX\n", (crc ^ CRC_OF_ZERO) & 0xffff, (uint32)j);
return;
用法:
uint16 test[] = 0x0123, 0x4567, 0x89AB, 0xCDEF; // prefix should be 0x0CD8236A
bruteforcecrc32(revcrc32(test, 4, 0L));
【讨论】:
它是“samgak”。答案已被所有者 samgak 删除。 那是Samgak - 显然他删除了他的答案,因为你的函数“不是CRC32的正确实现”,即使他的解决方案有效(基本上,他同意马克阿德勒的观点)。因此,您可能需要再看一遍,以确认一下。 谢谢你的名字,我希望他能再发一次。我也知道这不是正确/通常的实现,这就是为什么我在尝试以通常的方式进行一周后在这里写信的原因。有人实现了这种CRC32,我对此无能为力,给我的一切都在我问题的第一段中给了你。再次感谢您 你已经说过这实际上不是你得到的。您将获得的内容修改为“将所有内容放在一起”。 您没有冒犯,但如果您不显示最初提供的内容,我们将无法帮助您。你假设你在“缩短代码”时没有搞砸什么,这样它“可读性更好”。但是,我们已经有一个示例,其中“与 *data 的 XOR 是我的错误,是的”,“认为它会有所帮助”。【参考方案3】:替代方法。假设xorout = 0,如果不是,则计算出正常的crc后,再用crc ^= xorout去掉它。这里的方法将正常的 crc 乘以 (1/2)%(crc polynomial) 提高到(消息大小以位为单位)幂 %(crc 多项式),相当于向后循环。如果消息大小是固定的,则映射是固定的,时间复杂度为 O(1)。否则,为 O(log(n))。
此示例代码使用 Visual Studio 和内部无进位乘法 (PCLMULQDQ),它使用 XMM(128 位)寄存器。 Visual Studio 使用 __m128i 类型来表示整数 XMM 值。
#include <stdio.h>
#include <stdlib.h>
#include <intrin.h>
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
#define POLY (0x104c11db7ull)
#define POLYM ( 0x04c11db7u)
static uint32_t crctbl[256];
static __m128i poly; /* poly */
static __m128i invpoly; /* 2^64 / POLY */
void GenMPoly(void) /* generate __m128i poly info */
uint64_t N = 0x100000000ull;
uint64_t Q = 0;
for(size_t i = 0; i < 33; i++)
Q <<= 1;
if(N&0x100000000ull)
Q |= 1;
N ^= POLY;
N <<= 1;
poly.m128i_u64[0] = POLY;
invpoly.m128i_u64[0] = Q;
void GenTbl(void) /* generate crc table */
uint32_t crc;
uint32_t c;
uint32_t i;
for(c = 0; c < 0x100; c++)
crc = c<<24;
for(i = 0; i < 8; i++)
/* assumes twos complement */
crc = (crc<<1)^((0-(crc>>31))&POLYM);
crctbl[c] = crc;
uint32_t GenCrc(uint8_t * bfr, size_t size) /* generate crc */
uint32_t crc = 0xffffffffu;
while(size--)
crc = (crc<<8)^crctbl[(crc>>24)^*bfr++];
return(crc);
/* carryless multiply modulo poly */
uint32_t MpyModPoly(uint32_t a, uint32_t b) /* (a*b)%poly */
__m128i ma, mb, mp, mt;
ma.m128i_u64[0] = a;
mb.m128i_u64[0] = b;
mp = _mm_clmulepi64_si128(ma, mb, 0x00); /* p[0] = a*b */
mt = _mm_clmulepi64_si128(mp, invpoly, 0x00); /* t[1] = (p[0]*((2^64)/POLY))>>64 */
mt = _mm_clmulepi64_si128(mt, poly, 0x01); /* t[0] = t[1]*POLY */
return mp.m128i_u32[0] ^ mt.m128i_u32[0]; /* ret = p[0] ^ t[0] */
/* exponentiate by repeated squaring modulo poly */
uint32_t PowModPoly(uint32_t a, uint32_t b) /* pow(a,b)%poly */
uint32_t prd = 0x1u; /* current product */
uint32_t sqr = a; /* current square */
while(b)
if(b&1)
prd = MpyModPoly(prd, sqr);
sqr = MpyModPoly(sqr, sqr);
b >>= 1;
return prd;
int main()
uint32_t inv; /* 1/2 % poly, constant */
uint32_t fix; /* fix value, constant if msg size fixed */
uint32_t crc; /* crc at end of msg */
uint32_t pre; /* prefix for msg */
uint8_t msg[13] = 0x00,0x00,0x00,0x00,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39;
GenMPoly(); /* generate __m128i polys */
GenTbl(); /* generate crc table */
inv = PowModPoly(2, 0xfffffffeu); /* inv = 2^(2^32-2) % Poly = 1/2 % poly */
fix = PowModPoly(inv, 8*sizeof(msg)); /* fix value */
crc = GenCrc(msg, sizeof(msg)); /* calculate normal crc */
pre = MpyModPoly(fix, crc); /* convert to prefix */
printf("crc = %08x pre = %08x ", crc, pre);
msg[0] = (uint8_t)(pre>>24); /* store prefix in msg */
msg[1] = (uint8_t)(pre>>16);
msg[2] = (uint8_t)(pre>> 8);
msg[3] = (uint8_t)(pre>> 0);
crc = GenCrc(msg, sizeof(msg)); /* check result */
if(crc == 0)
printf("passed\n");
else
printf("failed\n");
return 0;
【讨论】:
以上是关于请将CRC16的C语言算法,改造为JAVA语言算法,万分感谢!的主要内容,如果未能解决你的问题,请参考以下文章
CRC16算法之一:CRC16-CCITT-FALSE算法的java实现