我有一个应用程序可以解码来自磁条阅读器的数据。但是,我很难得到我计算的LRC校验字节以匹配卡片上的字节。如果我每次使用3个音轨就能获得3张卡片,我猜想下面的算法可以在这些卡片中的9个音轨中的4个上工作。
我正在使用的算法看起来像这样(C#):
private static char GetLRC(string s, int start, int end)
{
int result = 0;
for (int i = start; i <= end; i++)
{
result ^= Convert.ToByte(s[i]);
}
return Convert.ToChar(result);
}
这是未通过检查的曲目3数据的示例。在此卡上,轨道2匹配,但轨道1也失败。
0 1 2 3 4 5 6 7 8 9 A B C D E F
00 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5
10 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7
20 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8
30 8 8 8 9 9 9 9 9 9 9 9 9 9 0 0 0
40 0 0 0 0 0 0 0 1 2 3 4 1 1 1 1 1
50 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3
60 3 3 3 3 3 3 3 3
扇区定界符是';'它以“?”结尾。
此轨道的LRC字节为0x30。不幸的是,上面的算法按照以下计算计算LRC为0x00(对于它的长度道歉。我想彻底):
00 ^ 3b = 3b ';'
3b ^ 33 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 34 = 3c
3c ^ 34 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 35 = 3d
3d ^ 35 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 36 = 3e
3e ^ 36 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 37 = 3f
3f ^ 37 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 38 = 30
30 ^ 38 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 39 = 31
31 ^ 39 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 30 = 38
38 ^ 30 = 08
08 ^ 31 = 39
39 ^ 32 = 0b
0b ^ 33 = 38
38 ^ 34 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 31 = 3d
3d ^ 31 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 32 = 3e
3e ^ 32 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 33 = 0c
0c ^ 33 = 3f
3f ^ 3f = 00 '?'
如果有人可以指出如何修复我的算法,我将不胜感激。
谢谢, PaulH
编辑:
这样你就可以看出我是否在LRC计算中意外丢失了任何字节或包含了错误的字节(最后的'。'实际上是'\ r')。来自所有三个轨道的完整数据:
0 1 2 3 4 5 6 7 8 9 A B C D E F
00 % U V W X Y Z 0 1 2 3 4 5 6 7 8
10 9 9 A B C D E F G H I J K L M N
20 O P Q R S T U V W X Y Z 1 2 3 0
30 1 2 3 4 5 6 7 8 9 A B C D E F G
40 H I J K L M N O P Q R S T ? 3 ;
50 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9
60 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
70 6 7 8 9 0 ? 5 ; 3 4 4 4 4 4 4 4
80 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6
90 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7
A0 7 8 8 8 8 8 8 8 8 8 8 9 9 9 9 9
B0 9 9 9 9 9 0 0 0 0 0 0 0 0 0 0 1
C0 2 3 4 1 1 1 1 1 1 1 1 1 1 2 2 2
D0 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3
E0 ? 0 .
GetLRC()
算法按建议重新检测,只显示奇数次的XOR字节:
private static char GetLRC(string s, int start, int end)
{
int result = 0;
byte cur_byte = Convert.ToByte(s[start]);
int count = 0;
for (int i = start; i <= end; i++)
{
byte b = Convert.ToByte(s[i]);
if (cur_byte != b)
{
if (count % 2 != 0)
{
result ^= cur_byte;
}
cur_byte = b;
count = 0;
}
++count;
}
if (count % 2 != 0)
{
result ^= cur_byte;
}
return Convert.ToChar(result);
}
新GetLRC()
函数采取的计算步骤:
00 ^ 3b = 3b ';'
3b ^ 33 = 08
08 ^ 31 = 39
39 ^ 32 = 0b
0b ^ 33 = 38
38 ^ 34 = 0c
0c ^ 33 = 3f
3f ^ 3f = 00 '?'
问题:LRC字节是来自卡本身还是由读卡器固件添加? (也许这可能是一个固件错误)
答案 0 :(得分:1)
我可以提出建议吗?将数据存储为运行长度,如果运行长度为奇数,则仅执行xor - 然后仅执行一次(runLength&amp; 0x01)次。这将摆脱大量无用的工作,并使发生的事情变得更加清晰。这样做会产生:
Run Lengths:
(01,3b)(01,33)(10,34)(10,35)(10,36)(10,37)(10,38)(10,39)(10,30)
(01,31)(01,32)(01,33)(01,34)(10,31)(10,32)(09,33)(1,3f)
做偶数/奇数事情给出:
3b ^ 33 ^ 31 ^ 32 ^ 33 ^ 34 ^ 33 ^ 3f
08-->39-->0B-->38-->0C-->3F-->00
看起来更简单,更清洁。我的猜测是,查看您的数据,您的数据流中有一个额外的30或1短。添加额外的30可以获得答案:
3b ^ 33 ^ 31 ^ 32 ^ 33 ^ 34 ^ 33 ^ 30 ^ 3F
08-->39-->0B-->38-->0C-->3F-->0F-->30
除此之外,我会继续挖掘......
您可以在输入参数中添加一些断言或其他验证吗?我讨厌看到超出界限的开始/结束导致兴奋和/或空字符串。此外,是否有可能在开始结束时关闭?包容性/独家数据范围?这可能会导致数据末尾的额外0x030从存储在轨道3末尾的0转换为0x30。此外,是否有可能存在损坏的数据或损坏的LRU?显然,这是你的支票试图抓住的那种东西。也许它抓住了什么?
答案 1 :(得分:1)
关于LRC的算法被纠正,但计算LRC的数据格式可能是错误的。 (这取决于您的MSR阅读器)
有两种格式的轨道由ANSI / ISO(Alpha和BCD)定义。 二进制编码与ASCII不同。
在这种情况下,启动哨兵是';' ,所以格式应该是BCD。 (Alpha start sentinel是'%')
LRC使用“真实跟踪数据”来计算(不包括奇偶校验位),
Convert rule
ASCII to BCD ->(ASCII - 0x30)
--Data Bits-- Parity
b1 b2 b3 b4 b5 Character Function
0 0 0 0 1 0 (0H) Data
1 0 0 0 0 1 (1H) "
0 1 0 0 0 2 (2H) "
1 1 0 0 1 3 (3H) "
0 0 1 0 0 4 (4H) "
1 0 1 0 1 5 (5H) "
0 1 1 0 1 6 (6H) "
1 1 1 0 0 7 (7H) "
0 0 0 1 0 8 (8H) "
1 0 0 1 1 9 (9H) "
0 1 0 1 1 : (AH) Control
1 1 0 1 0 ; (BH) Start Sentinel
0 0 1 1 1 < (CH) Control
1 0 1 1 0 = (DH) Field Separator
0 1 1 1 0 > (EH) Control
1 1 1 1 1 ? (FH) End Sentinel
在您的样本中,
P.S。 ASCII转换为Alpha
if(bASCII >= 0x20 && bASCII <= 0x5B)
{
return(bASCII - 0x20);
}
else if(bASCII >= 0x5C && bASCII <= 0x5F)
{
return(bASCII - 0x1F);
}
答案 2 :(得分:0)
您的算法与LRC algorithm in Wikipedia's article不匹配。你确定你使用的是正确的算法吗?