I have an application that decodes data from a magnetic stripe reader. But, I'm having difficulty getting my calculated LRC check byte to match the one on the cards. If I were to grab 3 cards each with 3 tracks, I would guess the algorithm below would work on 4 of the 9 tracks in those cards.
The algorithm I'm using looks like this (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);
}
This is an example of track 3 data that fails the check. On this card, track 2 matched, but track 1 also failed.
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
The sector delimiter is ';' and it ends with a '?'.
The LRC byte from this track is 0x30. Unfortunately, the algorithm above computes an LRC of 0x00 per the following calculation (apologies for its length. I want to be thorough):
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 '?'
If anybody can point out how to fix my algorithm, I would appreciate it.
Thanks,
PaulH
Edit:
So that you can see if I'm accidentally missing any bytes in my LRC calculation or including the wrong ones (the final '.' is actually a '\r'). The complete data from all three tracks:
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 .
The GetLRC() algorithm re-instrumented as suggested to only XOR bytes that appear an odd number of times:
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);
}
The calculation steps taken by the new GetLRC() function:
00 ^ 3b = 3b ';'
3b ^ 33 = 08
08 ^ 31 = 39
39 ^ 32 = 0b
0b ^ 33 = 38
38 ^ 34 = 0c
0c ^ 33 = 3f
3f ^ 3f = 00 '?'
Question: Does the LRC byte come from the card itself or is it being added by the reader firmware? (i.e. perhaps this is a firmware bug)
Can I make a suggestion? Store your data as run lengths and only do the xor if the run length is odd - and then only do it once (runLength & 0x01) times. That will get rid of a ton of the worthless bit work and make it clearer on what is occuring. Doing that yields:
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)
Doing the even/odd thing gives:
3b ^ 33 ^ 31 ^ 32 ^ 33 ^ 34 ^ 33 ^ 3f
08-->39-->0B-->38-->0C-->3F-->00
Much simpler and cleaner to look at. My guess is that looking at your data, that there is an extra 30 somewhere in your data stream or 1 short. Adding that extra 30 gets you your answer:
3b ^ 33 ^ 31 ^ 32 ^ 33 ^ 34 ^ 33 ^ 30 ^ 3F
08-->39-->0B-->38-->0C-->3F-->0F-->30
Beyond that, I'll keep digging...
Can you add some asserts or other validation to your input parameters? I'd hate to see out of bounds start/end causing excitement and/or a null string. Also, is there a possibility of an off by one with start end? Inclusive/exclusive data range? That could account for an extra 0x030 at the end of your data from a 0 stored at the end of your track 3 being converted to a 0x30. Also, is there any possibility of having either corrupt data or a corrupt LRU? Obviously, this is the kind of thing your check is trying to catch. Perhaps it caught something?
Algorithm about LRC is corrected, but the format of data to calculate LRC maybe wrong.
(it depends on your MSR reader)
There are two format of track define by ANSI/ISO (Alpha and BCD).
The coding of binary is different to ASCII.
In this case, start sentinel is ';' ,so the format should be BCD.
(Alpha start sentinel is '%')
LRC is use "Real track data" to calculate (not include parity bit),
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
In your sample,
Convert ASCII track data to BCD format.
Use BCD data to calculate LRC, the result is 0x00.
Then convert LRC(BCD to ASCII), finally got LRC = 0x30.
P.S. ASCII convert to Alpha
if(bASCII >= 0x20 && bASCII <= 0x5B)
{
return(bASCII - 0x20);
}
else if(bASCII >= 0x5C && bASCII <= 0x5F)
{
return(bASCII - 0x1F);
}
Your algorithm doesn't match the LRC algorithm in Wikipedia's article. Are you sure you're using the correct algorithm?
Related
I am trying to produce a square-formatted multiplication table with the output at the end using code below:
def multiplicationTable(maxValue):
for i in range(1, maxvalue):
for j in range(1, maxvalue):
print(("{:6d}".format(i * j,)), end='')
print()
print(multiplicationTable(1)
print(multiplicationTable(5))
print(multiplicationTable(10))
1
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
I get an error:
File "", line 7
print(multiplicationTable(5))
^
SyntaxError: invalid syntax
print(multiplicationTable(1) is missing a closing ).
You are using maxValue (with capital V) in your function definition while using maxvalue (with small v) in the function body.
Here is the new version:
def multiplicationTable(maxvalue): # maxvalue, not maxValue
for i in range(1, maxvalue+1):
for j in range(1, maxvalue+1):
print(("{:6d}".format(i * j,)), end='')
print()
multiplicationTable(1)
multiplicationTable(5)
multiplicationTable(10)
EDIT 1: Changed range(1, maxvalue) to range(1, maxvalue+1)
EDIT 2: Changed print(multiplicationTable(n)) to multiplicationTable(n)
I have a bed file named coverage.bed. When I execute head coverage.bed, this is the beginning of what outputs:
chr start end . . strand length CG CA CT CC TG AG GG
chr1 3000380 3000440 . . + 172 0 2 9 2
chr1 3000492 3000552 . . + 172 0 1 9 1
chr1 3000593 3000653 . . + 1055 0 4 7 4
However, when I view the file using gedit coverage.bed, I see that this is the correct first 3 lines:
chr start end . . strand length CG CA CT CC TG AG GG
chr1 3000380 3000440 . . + 172 0 2 9 1 3 5 2
chr1 3000492 3000552 . . + 172 0 1 9 2 8 1 1
chr1 3000593 3000653 . . + 1055 0 4 7 3 6 5 4
Why is this happening? A python script outputted this file-- could it be possible that there is something wrong with the code that would lead to this error?
Edit: the output of sed -n 2p coverage.bed | hexdump -C is:
00000000 63 68 72 31 09 33 30 30 30 33 38 30 09 33 30 30 |chr1.3000380.300|
00000010 30 34 34 30 09 2e 09 2e 09 2b 09 31 37 32 09 30 |0440.....+.172.0|
00000020 09 32 09 39 09 31 09 33 09 35 09 32 0d 0a |.2.9.1.3.5.2..|
0000002e
Application is in C, to read only NFC card details(card number & date). Following the steps below
CardRead("1PAY.SYS.DDF01", "PSE1");
Ex:APDU - (0x00, 0xA4, 0x04, 0x00, PSE1,00) or
CardRead("2PAY.SYS.DDF01", "PSE2");
Ex:APDU - (0x00, 0xA4, 0x04, 0x00, PSE2,00)
Select the AID Get the AID from response data.
Ex:APDU - (0x00, 0xA4, 0x04, 0x00, AID,00)
ReadRecord - Want to know how to calculate SFI & P1,P2 values.
Is PDOL required or only Read Record command is enough to read track1/2 data?
After step 3 data received is 3 6F 38 84 7 A0 0 0 0 4 10 10 A5 2D 50 A 4D 41 53 54 45 52 43 41 52 44 87 1 1 5F 2D 2 65 6E 9F 38 9 9F 1D 8 9F 1A 2 9F 35 1 BF C A 9F 6E 7 8 40 0 0 32 31 0 90 0 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 9F 65 2 0 E0 9F 66 2 F 1E 9F 67 1 4 9F 6B 13 51 80 84 8 2 59 9 27 D2 20 92 1 0 0 0 0 0 0.
This is PDOL information: 9F 38 9 9F 1D 8 9F 1A 2 9F 35 1.
Please let me know how to frame next command PDOL/ReadRecord from the above data to read track1/track2 data.
Download EMV Book 3, read section 10.2 Read Application Data. It has it all. Find below in case you cant get the document.
I am trying to remove rows based on 4th column value is equal to 7 and 5th column value less than 30 from my text file using awk.
Here is my text file
1 1 2017 7 00 00 95.197469 112.803277
1 1 2017 7 05 00 94.139040 113.255244
1 1 2017 7 10 00 93.084220 113.715022
1 1 2017 7 15 00 92.033141 114.182867
1 1 2017 7 20 00 90.985940 114.659045
1 1 2017 7 25 00 89.500772 115.143830
1 1 2017 7 30 00 88.574990 115.637504
1 1 2017 7 35 00 87.614221 116.140360
1 1 2017 7 40 00 86.633495 116.652701
1 1 2017 7 45 00 85.642547 117.174839
1 1 2017 7 50 00 84.647055 117.707097
1 1 2017 7 55 00 83.650410 118.249809
1 1 2017 8 00 00 82.654745 118.803319
1 1 2017 8 05 00 81.661486 119.367982
1 1 2017 8 10 00 80.671646 119.944164
1 1 2017 8 15 00 79.685987 120.532243
1 1 2017 8 20 00 78.705118 121.132609
1 1 2017 8 25 00 77.729550 121.745662
1 1 2017 8 30 00 76.759731 122.371816
1 1 2017 8 35 00 75.796072 123.011494
1 1 2017 8 40 00 74.838956 123.665132
1 1 2017 8 45 00 73.888755 124.333179
1 1 2017 8 50 00 72.945832 125.016092
1 1 2017 8 55 00 72.010551 125.714342
1 1 2017 9 00 00 71.083276 126.428408
With awk:
awk '$4!=7 || $5>=30 {print}' file
Output:
1 1 2017 7 30 00 88.574990 115.637504
1 1 2017 7 35 00 87.614221 116.140360
1 1 2017 7 40 00 86.633495 116.652701
1 1 2017 7 45 00 85.642547 117.174839
1 1 2017 7 50 00 84.647055 117.707097
1 1 2017 7 55 00 83.650410 118.249809
1 1 2017 8 00 00 82.654745 118.803319
1 1 2017 8 05 00 81.661486 119.367982
1 1 2017 8 10 00 80.671646 119.944164
1 1 2017 8 15 00 79.685987 120.532243
1 1 2017 8 20 00 78.705118 121.132609
1 1 2017 8 25 00 77.729550 121.745662
1 1 2017 8 30 00 76.759731 122.371816
1 1 2017 8 35 00 75.796072 123.011494
1 1 2017 8 40 00 74.838956 123.665132
1 1 2017 8 45 00 73.888755 124.333179
1 1 2017 8 50 00 72.945832 125.016092
1 1 2017 8 55 00 72.010551 125.714342
1 1 2017 9 00 00 71.083276 126.428408
Perhaps a more concise awk
Removing line where field 4 equals 7 and field 5 less than 30
$ awk '!($4==7 && $5<30)' case_file_48485025
Output
1 1 2017 7 30 00 88.574990 115.637504
1 1 2017 7 35 00 87.614221 116.140360
1 1 2017 7 40 00 86.633495 116.652701
1 1 2017 7 45 00 85.642547 117.174839
1 1 2017 7 50 00 84.647055 117.707097
1 1 2017 7 55 00 83.650410 118.249809
1 1 2017 8 00 00 82.654745 118.803319
1 1 2017 8 05 00 81.661486 119.367982
1 1 2017 8 10 00 80.671646 119.944164
.
.
How it works
By default awk prints a line if it sees a non-zero value as its command
!($4==7 && $5<30) would evaluate to zero when your condition is met and hence awk doesn't print.
This might work for you (GNU sed):
sed '/^.........7.[0-2]/d' file
Delete a line that has a 7 in the 4th column and 0 to 2 as the first character of the 5th column.
i am trying to transpose a table (10k rows X 10K cols) using the following script.
A simple data example
$ cat rm1
t1 t2 t3
n1 1 2 3
n2 2 3 44
n3 1 1 1
$ sh transpose.sh rm1
n1 n2 n3
t1 1 2 1
t2 2 3 1
t3 3 44 1
However, I am getting memory error. Any help would be appreciated.
awk -F "\t" '{
for (f = 1; f <= NF; f++)
a[NR, f] = $f
}
NF > nf { nf = NF }
END {
for (f = 1; f <= nf; f++)
for (r = 1; r <= NR; r++)
printf a[r, f] (r==NR ? RS : FS)
}'
Error
awk: cmd. line:2: (FILENAME=input FNR=12658) fatal: dupnode: r->stptr: can't allocate 10 bytes of memory (Cannot allocate memory)
Here's one way to do it, as I mentioned in my comments, in chunks. Here I show the mechanics on a tiny 12r x 10c file, but I also ran a chunk of 1000 rows on a 10K x 10K file in not much more than a minute (Mac Powerbook).6
EDIT The following was updated to consider an M x N matrix with unequal number of rows and columns. The previous version only worked for an 'N x N' matrix.
$ cat et.awk
BEGIN {
start = chunk_start
limit = chunk_start + chunk_size - 1
}
{
n = (limit > NF) ? NF : limit
for (f = start; f <= n; f++) {
a[NR, f] = $f
}
}
END {
n = (limit > NF) ? NF : limit
for (f = start; f <= n; f++)
for (r = 1; r <= NR; r++)
printf a[r, f] (r==NR ? RS : FS)
}
$ cat t.txt
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9
B0 B1 B2 B3 B4 B5 B6 B7 B8 B9
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9
$ cat et.sh
inf=$1
outf=$2
rm -f $outf
for i in $(seq 1 2 12); do
echo chunk for rows $i $(expr $i + 1)
awk -v chunk_start=$i -v chunk_size=2 -f et.awk $inf >> $outf
done
$ sh et.sh t.txt t-transpose.txt
chunk for rows 1 2
chunk for rows 3 4
chunk for rows 5 6
chunk for rows 7 8
chunk for rows 9 10
chunk for rows 11 12
$ cat t-transpose.txt
10 20 30 40 50 60 70 80 90 A0 B0 C0
11 21 31 41 51 61 71 81 91 A1 B1 C1
12 22 32 42 52 62 72 82 92 A2 B2 C2
13 23 33 43 53 63 73 83 93 A3 B3 C3
14 24 34 44 54 64 74 84 94 A4 B4 C4
15 25 35 45 55 65 75 85 95 A5 B5 C5
16 26 36 46 56 66 76 86 96 A6 B6 C6
17 27 37 47 57 67 77 87 97 A7 B7 C7
18 28 38 48 58 68 78 88 98 A8 B8 C8
19 29 39 49 59 69 79 89 99 A9 B9 C9
And then running the first chunk on the huge file looks like:
$ time awk -v chunk_start=1 -v chunk_size=1000 -f et.awk tenk.txt > tenk-transpose.txt
real 1m7.899s
user 1m5.173s
sys 0m2.552s
Doing that ten times with the next chunk_start set to 1001, etc. (and appending with >> to the output, of course) should finally give you the full transposed result.
There is a simple and quick algorithm based on sorting:
1) Make a pass through the input, prepending the row number and column number to each field. Output is a three-tuple of row, column, value for each cell in the matrix. Write the output to a temporary file.
2) Sort the temporary file by column, then row.
3) Make a pass through the sorted temporary file, reconstructing the transposed matrix.
The two outer passes are done by awk. The sort is done by the system sort. Here's the code:
$ echo '1 2 3
2 3 44
1 1 1' |
awk '{ for (i=1; i<=NF; i++) print i, NR, $i}' |
sort -n |
awk ' NR>1 && $2==1 { print "" }; { printf "%s ", $3 }; END { print "" }'
1 2 1
2 3 1
3 44 1