mfrc522 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4595ef4728e8788e2448de76ce8b64ea6d0ae167
4
- data.tar.gz: 6c364cc01a7147ea40675152b6538017d8e67b09
3
+ metadata.gz: 3ae695036f039f29942ea9a3e46cb365fb1e4fe7
4
+ data.tar.gz: c144d7dcf96074d047a3eba55523a27f2b3a74fb
5
5
  SHA512:
6
- metadata.gz: 2f87dd8826b8e949b2a6813a035dbe598a3e24e69cba4da220ac7c5483aae6d3d5e6d948a2ad5f83967909fc7cad97c0a2e810d4c4187e5e11c2827f620258c8
7
- data.tar.gz: 1ea6d484be7cf70ded2e82549d2e853a5bbfbe6e6488fc0ff0ed917bce5e5b060696738c6eae97b2cda90b773ec560cf1a47424919aea11b2e6869b5d1193269
6
+ metadata.gz: ae5877e53851c774fdf68ac3ccb65fe3623d6a446e42e39f1ac843b0ecc8bcb7aaac68bf657ce632154d0e6876ee5786e884acebb9d9c53156818f6c9f1a8ecf
7
+ data.tar.gz: b8e8e5df57870a7da924c7a8dd207d2fa6ba89be281116c1b7ba5da5327bd3eb35b1e402bc80d61e06bce57293c8325f46dad25aca5409da129668c6f52e4ee7
data/lib/mfrc522.rb CHANGED
@@ -1,8 +1,19 @@
1
1
  require 'pi_piper'
2
2
 
3
+ # For 3DES auth
4
+ require 'openssl'
5
+ require 'securerandom'
6
+
7
+ require 'mifare/base'
8
+ require 'mifare/classic'
9
+ require 'mifare/ultralight'
10
+ require 'mifare/ultralight_c'
11
+ require 'mifare/plus'
12
+ require 'mifare/des_fire'
13
+
3
14
  include PiPiper
4
15
 
5
- class Mfrc522
16
+ class MFRC522
6
17
 
7
18
  # PICC commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
8
19
  PICC_REQA = 0x26 # REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
@@ -26,8 +37,8 @@ class Mfrc522
26
37
  # The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
27
38
  # The PICC_MF_READ and PICC_MF_WRITE can also be used for MIFARE Ultralight.
28
39
  PICC_UL_WRITE = 0xA2 # Writes one 4 byte page to the PICC.
29
- # The commands here is for 3DES Authentication
30
- PICC_MF_3DES_AUTH = 0x1A
40
+ # The commands here is for Ultralight 3DES Authentication
41
+ PICC_UL_3DES_AUTH = 0x1A
31
42
  #
32
43
  PICC_MF_ACK = 0x0A # Mifare Acknowledge
33
44
 
@@ -128,7 +139,7 @@ class Mfrc522
128
139
  antenna_on # Turn antenna on. They were disabled by the reset.
129
140
  end
130
141
 
131
- # MFRC522 software reset
142
+ # PCD software reset
132
143
  def soft_reset
133
144
  write_spi(CommandReg, PCD_SoftReset)
134
145
  sleep 1.0 / 20.0 # wait 50ms
@@ -177,8 +188,7 @@ class Mfrc522
177
188
 
178
189
  # Turn antenna on
179
190
  def antenna_on
180
- value = read_spi(TxControlReg)
181
- write_spi_set_bitmask(TxControlReg, 0x03) if (value & 0x03) != 0x03
191
+ write_spi_set_bitmask(TxControlReg, 0x03)
182
192
  end
183
193
 
184
194
  # Turn antenna off
@@ -240,7 +250,7 @@ class Mfrc522
240
250
  return :status_ok
241
251
  end
242
252
 
243
- # PICC transceive helper
253
+ # PCD transceive helper
244
254
  def communicate_with_picc(command, send_data, framing_bit = 0, check_crc = false)
245
255
  wait_irq = 0x00
246
256
  wait_irq = 0x10 if command == PCD_MFAuthent
@@ -309,7 +319,7 @@ class Mfrc522
309
319
  return :status_ok
310
320
  end
311
321
 
312
- # Instruct PICC in ACTIVE state go to HALT
322
+ # Instruct PICC in ACTIVE state go to HALT state
313
323
  def picc_halt
314
324
  buffer = [PICC_HLTA, 0]
315
325
 
@@ -370,6 +380,7 @@ class Mfrc522
370
380
  # ensure there's nothing weird in buffer
371
381
  if buffer.size != 6 && !buffer.select{|b| !buffer.is_a?(Fixnum)}.empty?
372
382
  current_level_known_bits = 0
383
+ buffer = []
373
384
  next
374
385
  end
375
386
 
@@ -439,6 +450,29 @@ class Mfrc522
439
450
  return :status_ok, uid, sak
440
451
  end
441
452
 
453
+ # Trying to wake it up again
454
+ def reestablish_picc_communication(uid)
455
+ status = picc_halt
456
+ return status if status != :status_ok
457
+
458
+ status = picc_request(PICC_WUPA)
459
+ return status if status != :status_ok
460
+
461
+ status, new_uid, new_sak = picc_select
462
+ return status if status != :status_ok
463
+
464
+ if uid == new_uid
465
+ return :status_ok
466
+ else
467
+ return :status_different_card_detected
468
+ end
469
+ end
470
+
471
+ # ISO/IEC 14443-4 select
472
+ def iso_select
473
+
474
+ end
475
+
442
476
  # Lookup error message
443
477
  def error_type(error)
444
478
  case error
@@ -462,6 +496,12 @@ class Mfrc522
462
496
  'Incorrect select acknowledge'
463
497
  when :status_auth_failed
464
498
  'Authentication failed'
499
+ when :status_data_length_error
500
+ 'Incorrect input data length'
501
+ when :status_incorrect_input
502
+ 'Incorrect input'
503
+ when :status_different_card_detected
504
+ 'Different card detected while reselecting'
465
505
  when :status_error
466
506
  'Something went wrong'
467
507
  else
@@ -470,36 +510,51 @@ class Mfrc522
470
510
  end
471
511
 
472
512
  # Lookup PICC name using sak
473
- def picc_type(sak)
474
- sak &= 0x7F
475
-
476
- case sak
477
- when 0x04
478
- 'PICC_TYPE_NOT_COMPLETE'
479
- when 0x09
480
- 'PICC_TYPE_MIFARE_MINI'
481
- when 0x08
482
- 'PICC_TYPE_MIFARE_1K'
483
- when 0x18
484
- 'PICC_TYPE_MIFARE_4K'
485
- when 0x00
486
- 'PICC_TYPE_MIFARE_UL'
487
- when 0x10, 0x11
488
- 'PICC_TYPE_MIFARE_PLUS'
489
- when 0x01
490
- 'PICC_TYPE_TNP3XXX'
491
- when 0x20
492
- 'PICC_TYPE_ISO_14443_4'
493
- when 0x40
494
- 'PICC_TYPE_ISO_18092'
495
- else
496
- 'PICC_TYPE_UNKNOWN'
513
+ def identify_model(sak)
514
+ # SAK coding separation reference:
515
+ # http://cache.nxp.com/documents/application_note/AN10833.pdf
516
+ # http://www.nxp.com/documents/application_note/130830.pdf
517
+ if sak & 0x04 != 0
518
+ return :picc_uid_not_complete
497
519
  end
498
- end
499
520
 
500
- # Check if Mifare PICC
501
- def mifare?(sak)
502
- sak & 0x20 != 1
521
+ if sak & 0x02 != 0
522
+ return :picc_reserved_future_use
523
+ end
524
+
525
+ if sak & 0x08 != 0
526
+ if sak & 0x10 != 0
527
+ return :picc_mifare_4k
528
+ end
529
+
530
+ if sak & 0x01 != 0
531
+ return :picc_mifare_mini
532
+ end
533
+
534
+ return :picc_mifare_1k
535
+ end
536
+
537
+ if sak & 0x10 != 0
538
+ if sak & 0x01 != 0
539
+ return :picc_mifare_plus_4k_sl2
540
+ end
541
+
542
+ return :picc_mifare_plus_2k_sl2
543
+ end
544
+
545
+ if sak == 0x00
546
+ return :picc_mifare_ultralight
547
+ end
548
+
549
+ if sak & 0x20 != 0
550
+ return :picc_iso_14443_4
551
+ end
552
+
553
+ if sak & 0x40 != 0
554
+ return :picc_iso_18092
555
+ end
556
+
557
+ return :picc_unknown
503
558
  end
504
559
 
505
560
  # Start encrypted Crypto1 communication between reader and Mifare PICC
@@ -516,7 +571,7 @@ class Mfrc522
516
571
  #
517
572
  buffer = [command, block_addr]
518
573
  buffer += sector_key[0..5]
519
- buffer += uid[-4..-1]
574
+ buffer += uid[0..3]
520
575
 
521
576
  status, _received_data, _valid_bits = communicate_with_picc(PCD_MFAuthent, buffer)
522
577
 
@@ -531,50 +586,55 @@ class Mfrc522
531
586
  write_spi_clear_bitmask(Status2Reg, 0x08) # Clear MFCrypto1On bit
532
587
  end
533
588
 
534
- def mifare_3des_authenticate(des_key)
535
- require 'openssl'
536
- require 'securerandom'
537
-
538
- # Cipher
539
- cipher = OpenSSL::Cipher.new 'des-ede3-cbc'
540
- cipher.key = [des_key*2].pack('H*')
541
- cipher.padding = 0
542
-
589
+ def mifare_ultralight_3des_check
543
590
  # Ask for authentication
544
- buffer = [PICC_MF_3DES_AUTH, 0x00]
591
+ buffer = [PICC_UL_3DES_AUTH, 0x00]
545
592
  status, received_data = mifare_transceive(buffer)
546
593
  return status if status != :status_ok
547
594
  return :status_unknown_data if received_data[0] != 0xAF
548
595
 
596
+ return :status_ok, received_data
597
+ end
598
+
599
+ def mifare_ultralight_3des_authenticate(des_key)
600
+ status, received_data = mifare_ultralight_3des_check
601
+ return status if status != :status_ok
602
+
549
603
  # Use received data as IV for next transmission
550
604
  next_iv = received_data[1..8]
551
605
 
606
+ # Cipher
607
+ cipher = OpenSSL::Cipher.new 'des-ede3-cbc'
608
+ cipher.key = [des_key*2].pack('H*')
609
+ cipher.padding = 0
610
+
552
611
  # Decrypt challenge random number and rotate it by 8 bits
553
612
  cipher.decrypt
554
613
  cipher.iv = "\x00"*8
555
614
  challenge = received_data[1..8].pack('C*')
556
615
  challenge = cipher.update(challenge) + cipher.final
557
- challenge.rotate!
616
+ challenge = challenge.bytes.rotate
558
617
 
559
618
  # Generate 8 bytes random number and encrypt the response
560
619
  random_number = SecureRandom.random_bytes(8)
561
620
  cipher.encrypt
562
- cipher.iv = next_iv
563
- response = cipher.update(challenge.pack('C*') + random_number) + cipher.final
621
+ cipher.iv = next_iv.pack('C*')
622
+ response = cipher.update(random_number + challenge.pack('C*')) + cipher.final
623
+ response = response.bytes
564
624
 
565
625
  # Receive verification
566
- buffer = [0xAF, [response].unpack('H*')]
626
+ buffer = [0xAF] + response
567
627
  status, received_data = mifare_transceive(buffer)
568
628
  return status if status != :status_ok
569
629
  return :status_unknown_data if received_data[0] != 0x00
570
630
 
571
631
  # Check if verification matches random_number rotated by 8 bits
572
632
  cipher.decrypt
573
- cipher.iv = [response[-16..-1]].pack('H*')
633
+ cipher.iv = response[-8..-1].pack('C*')
574
634
  verification = received_data[1..8].pack('C*')
575
635
  verification = cipher.update(verification) + cipher.final
576
636
 
577
- if random_number.bytes.rotate! != verification
637
+ if random_number.bytes.rotate != verification.bytes
578
638
  picc_halt
579
639
  return :status_auth_failed
580
640
  end
@@ -595,10 +655,10 @@ class Mfrc522
595
655
 
596
656
  # Data exists, check CRC and return
597
657
  if received_data.size > 1
598
- return :status_crc_error if received_data.count < 2 || valid_bits != 0
658
+ return :status_crc_error if received_data.size < 3 || valid_bits != 0
599
659
 
600
660
  status = check_crc(received_data)
601
- return status, received_data
661
+ return status, received_data[0..-3]
602
662
  end
603
663
 
604
664
  # Data doesn't exist, check mifare acknowledge
@@ -608,133 +668,4 @@ class Mfrc522
608
668
  return :status_ok
609
669
  end
610
670
 
611
- # Read Mifare block address
612
- def mifare_read(block_addr)
613
- buffer = [PICC_MF_READ, block_addr]
614
-
615
- status, received_data = mifare_transceive(buffer)
616
- return status if status != :status_ok
617
-
618
- return :status_ok, received_data
619
- end
620
-
621
- # Write Mifare block address
622
- def mifare_write(block_addr, send_data)
623
- buffer = [PICC_MF_WRITE, block_addr]
624
-
625
- # Ask PICC if we can write to block_addr
626
- status = mifare_transceive(buffer)
627
- return status if status != :status_ok
628
-
629
- # Then start transfer our data
630
- status = mifare_transceive(send_data)
631
- return status if status != :status_ok
632
-
633
- return :status_ok
634
- end
635
-
636
- # Write helper for Mifare UL
637
- def mifare_ultralight_write(page, send_data)
638
- # Page 2-15, each 4 bytes
639
- buffer = [PICC_UL_WRITE, page]
640
- buffer += send_data[0..3]
641
-
642
- status = mifare_transceive(buffer)
643
- return status if status != :status_ok
644
-
645
- return :status_ok
646
- end
647
-
648
- # Helper for reading value block
649
- def mifare_get_value(block_addr)
650
- status, received_data = mifare_read(block_addr)
651
- return status if status != :status_ok
652
-
653
- value = (received_data[3] << 24) + (received_data[2] << 16) + (received_data[1] << 8) + received_data[0]
654
-
655
- return :status_ok, value
656
- end
657
-
658
- # Helper for writing value block
659
- def mifare_set_value(block_addr, value)
660
- # Value block format
661
- #
662
- # byte 0..3: 32 bit value in little endian
663
- # byte 4..7: copy of byte 0..3, with inverted bits (aka. XOR 255)
664
- # byte 8..11: copy of byte 0..3
665
- # byte 12: index of backup block (can be any value)
666
- # byte 13: copy of byte 12 with inverted bits (aka. XOR 255)
667
- # byte 14: copy of byte 12
668
- # byte 15: copy of byte 13
669
- buffer = []
670
- buffer[0] = value & 0xFF
671
- buffer[1] = (value >> 8) & 0xFF
672
- buffer[2] = (value >> 16) & 0xFF
673
- buffer[3] = (value >> 24) & 0xFF
674
- buffer[4] = ~buffer[0]
675
- buffer[5] = ~buffer[1]
676
- buffer[6] = ~buffer[2]
677
- buffer[7] = ~buffer[3]
678
- buffer[8] = buffer[0]
679
- buffer[9] = buffer[1]
680
- buffer[10] = buffer[2]
681
- buffer[11] = buffer[3]
682
- buffer[12] = block_addr
683
- buffer[13] = ~block_addr
684
- buffer[14] = buffer[12]
685
- buffer[15] = buffer[13]
686
-
687
- mifare_write(block_addr, buffer)
688
- end
689
-
690
- # Helper for increment, decrement, and restore command
691
- def mifare_two_step(command, block_addr, value)
692
- buffer = [command, block_addr]
693
- send_data = [ # Split integer into array of bytes
694
- value & 0xFF,
695
- (value >> 8) & 0xFF,
696
- (value >> 16) & 0xFF,
697
- (value >> 24) & 0xFF
698
- ]
699
-
700
- # Ask PICC if we can write to block_addr
701
- status = mifare_transceive(buffer)
702
- return status if status != :status_ok
703
-
704
- # Then start transfer our data
705
- status = mifare_transceive(send_data, true) # Accept timeout
706
- return status if status != :status_ok
707
-
708
- return :status_ok
709
- end
710
-
711
- # Mifare increment helper
712
- # MIFARE Classic only
713
- def mifare_increment(block_addr, delta)
714
- mifare_two_step(PICC_MF_INCREMENT, block_addr, delta)
715
- end
716
-
717
- # Mifare decrement helper
718
- # MIFARE Classic only
719
- def mifare_decrement(block_addr, delta)
720
- mifare_two_step(PICC_MF_DECREMENT, block_addr, delta)
721
- end
722
-
723
- # Mifare restore helper
724
- # MIFARE Classic only
725
- def mifare_restore(block_addr)
726
- mifare_two_step(PICC_MF_RESTORE, block_addr, 0)
727
- end
728
-
729
- # Mifare transfer helper
730
- # MIFARE Classic only
731
- def mifare_transfer(block_addr)
732
- buffer = [PICC_MF_TRANSFER, block_addr]
733
-
734
- status = mifare_transceive(buffer)
735
- return status if status != :status_ok
736
-
737
- return :status_ok
738
- end
739
671
  end
740
-
@@ -0,0 +1,22 @@
1
+ module Mifare
2
+ class Base
3
+
4
+ attr_reader :uid
5
+ attr_reader :sak
6
+
7
+ def initialize(pcd, uid, sak)
8
+ @pcd = pcd
9
+ @uid = uid
10
+ @sak = sak
11
+ end
12
+
13
+ def resume_communication
14
+ @pcd.reestablish_picc_communication(@uid)
15
+ end
16
+
17
+ def halt
18
+ @pcd.picc_halt
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,139 @@
1
+ module Mifare
2
+ class Classic < Base
3
+
4
+ def auth(block_addr, key = {})
5
+ if key[:a]
6
+ @pcd.mifare_crypto1_authenticate(MFRC522::PICC_MF_AUTH_KEY_A, block_addr, key[:a], @uid)
7
+ elsif key[:b]
8
+ @pcd.mifare_crypto1_authenticate(MFRC522::PICC_MF_AUTH_KEY_B, block_addr, key[:b], @uid)
9
+ else
10
+ :status_incorrect_input
11
+ end
12
+ end
13
+
14
+ def deauth
15
+ @pcd.mifare_crypto1_deauthenticate
16
+ end
17
+
18
+ def read(block_addr)
19
+ buffer = [MFRC522::PICC_MF_READ, block_addr]
20
+
21
+ status, received_data = @pcd.mifare_transceive(buffer)
22
+ return status if status != :status_ok
23
+
24
+ return :status_ok, received_data
25
+ end
26
+
27
+ def write(block_addr, send_data)
28
+ return :status_data_length_error if send_data.size != 16
29
+
30
+ buffer = [MFRC522::PICC_MF_WRITE, block_addr]
31
+
32
+ # Ask PICC if we can write to block_addr
33
+ status = @pcd.mifare_transceive(buffer)
34
+ return status if status != :status_ok
35
+
36
+ # Then start transfer our data
37
+ status = @pcd.mifare_transceive(send_data)
38
+ return status if status != :status_ok
39
+
40
+ return :status_ok
41
+ end
42
+
43
+ def read_value(block_addr)
44
+ status, received_data = read(block_addr)
45
+ return status if status != :status_ok
46
+
47
+ value = (received_data[3] << 24) +
48
+ (received_data[2] << 16) +
49
+ (received_data[1] << 8) +
50
+ received_data[0]
51
+
52
+ return :status_ok, value
53
+ end
54
+
55
+ def write_value(block_addr, value)
56
+ return :status_data_length_error if value.size > 4
57
+
58
+ # Value block format
59
+ #
60
+ # byte 0..3: 32 bit value in little endian
61
+ # byte 4..7: copy of byte 0..3, with inverted bits (aka. XOR 255)
62
+ # byte 8..11: copy of byte 0..3
63
+ # byte 12: index of backup block (can be any value)
64
+ # byte 13: copy of byte 12 with inverted bits (aka. XOR 255)
65
+ # byte 14: copy of byte 12
66
+ # byte 15: copy of byte 13
67
+ buffer = []
68
+ buffer[0] = value & 0xFF
69
+ buffer[1] = (value >> 8) & 0xFF
70
+ buffer[2] = (value >> 16) & 0xFF
71
+ buffer[3] = (value >> 24) & 0xFF
72
+ buffer[4] = ~buffer[0]
73
+ buffer[5] = ~buffer[1]
74
+ buffer[6] = ~buffer[2]
75
+ buffer[7] = ~buffer[3]
76
+ buffer[8] = buffer[0]
77
+ buffer[9] = buffer[1]
78
+ buffer[10] = buffer[2]
79
+ buffer[11] = buffer[3]
80
+ buffer[12] = block_addr
81
+ buffer[13] = ~block_addr
82
+ buffer[14] = buffer[12]
83
+ buffer[15] = buffer[13]
84
+
85
+ write(block_addr, buffer)
86
+ end
87
+
88
+ # Increment: Increments the contents of a block and stores the result in the internal Transfer Buffer
89
+ def increment(block_addr, delta)
90
+ two_step(MFRC522::PICC_MF_INCREMENT, block_addr, delta)
91
+ end
92
+
93
+ # Decrement: Decrements the contents of a block and stores the result in the internal Transfer Buffer
94
+ def decrement(block_addr, delta)
95
+ two_step(MFRC522::PICC_MF_DECREMENT, block_addr, delta)
96
+ end
97
+
98
+ # Restore: Moves the contents of a block into the internal Transfer Buffer
99
+ def restore(block_addr)
100
+ two_step(MFRC522::PICC_MF_RESTORE, block_addr, 0)
101
+ end
102
+
103
+ # Transfer: Writes the contents of the internal Transfer Buffer to a value block
104
+ def transfer(block_addr)
105
+ buffer = [MFRC522::PICC_MF_TRANSFER, block_addr]
106
+
107
+ status = @pcd.mifare_transceive(buffer)
108
+ return status if status != :status_ok
109
+
110
+ return :status_ok
111
+ end
112
+
113
+ private
114
+
115
+ # Helper for increment, decrement, and restore command
116
+ def two_step(command, block_addr, value)
117
+ return :status_data_length_error if value.size > 4
118
+
119
+ buffer = [command, block_addr]
120
+ send_data = [ # Split integer into array of bytes
121
+ value & 0xFF,
122
+ (value >> 8) & 0xFF,
123
+ (value >> 16) & 0xFF,
124
+ (value >> 24) & 0xFF
125
+ ]
126
+
127
+ # Ask PICC if we can write to block_addr
128
+ status = @pcd.mifare_transceive(buffer)
129
+ return status if status != :status_ok
130
+
131
+ # Then start transfer our data
132
+ status = @pcd.mifare_transceive(send_data, true) # Accept timeout
133
+ return status if status != :status_ok
134
+
135
+ return :status_ok
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,7 @@
1
+ module Mifare
2
+ class DESFire < Base
3
+ def self.say
4
+ puts 'yo'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Mifare
2
+ class Plus < Base
3
+ def self.say
4
+ puts 'Hello'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,44 @@
1
+ module Mifare
2
+ class Ultralight < Base
3
+
4
+ def initialize(pcd, uid, sak)
5
+ super
6
+ @is_c = false
7
+
8
+ # Check if Ultralight C
9
+ status, received_data = @pcd.mifare_ultralight_3des_check
10
+ if status == :status_ok
11
+ extend UltralightC
12
+ @is_c = true
13
+ end
14
+ resume_communication
15
+ end
16
+
17
+ def read(block_addr)
18
+ buffer = [MFRC522::PICC_MF_READ, block_addr]
19
+
20
+ status, received_data = @pcd.mifare_transceive(buffer)
21
+ return status if status != :status_ok
22
+
23
+ return :status_ok, received_data
24
+ end
25
+
26
+ def write(page, send_data)
27
+ return :status_data_length_error if send_data.size != 4
28
+
29
+ # Page 2-15, each 4 bytes
30
+ buffer = [MFRC522::PICC_UL_WRITE, page]
31
+ buffer += send_data
32
+
33
+ status = @pcd.mifare_transceive(buffer)
34
+ return status if status != :status_ok
35
+
36
+ return :status_ok
37
+ end
38
+
39
+ def is_c?
40
+ @is_c
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,42 @@
1
+ module Mifare
2
+ module UltralightC
3
+
4
+ # Using 16 bytes hex string for 3DES authentication
5
+ def auth(key)
6
+ @pcd.mifare_ultralight_3des_authenticate(key)
7
+ end
8
+
9
+ def write_des_key(key)
10
+ # key should be 16 bytes long
11
+ bytes = [key].pack('H*').unpack('C*')
12
+ return :status_data_length_error if bytes.size != 16
13
+
14
+ # Key1
15
+ write(0x2C, bytes[4..7].reverse)
16
+ write(0x2D, bytes[0..3].reverse)
17
+ # Key2
18
+ write(0x2E, bytes[12..15].reverse)
19
+ write(0x2F, bytes[8..11].reverse)
20
+ end
21
+
22
+ def counter_increment(value)
23
+ # you can set any value between 0x0000 to 0xFFFF on the first write (initialize)
24
+ # after initialized, counter can only be incremented by 0x01 ~ 0x0F
25
+ write(0x29, [value & 0xFF, (value >> 8) & 0xFF, 0x00, 0x00])
26
+ end
27
+
28
+ def enable_protection_from(block_addr)
29
+ # authentication will be required from `block_addr` to 0x2F
30
+ # valid value are from 0x03 to 0x30
31
+ # set to 0x30 to disable memory protection
32
+ write(0x2A, [block_addr & 0x3F, 0x00, 0x00, 0x00])
33
+ end
34
+
35
+ def set_protection_type(type)
36
+ # set to 0 for read-write access restriction (default)
37
+ # set to 1 for write access restriction
38
+ write(0x2B, [type & 0x01, 0x00, 0x00, 0x00])
39
+ end
40
+
41
+ end
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mfrc522
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - atitan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-22 00:00:00.000000000 Z
11
+ date: 2016-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pi_piper
@@ -37,6 +37,12 @@ extensions: []
37
37
  extra_rdoc_files: []
38
38
  files:
39
39
  - lib/mfrc522.rb
40
+ - lib/mifare/base.rb
41
+ - lib/mifare/classic.rb
42
+ - lib/mifare/des_fire.rb
43
+ - lib/mifare/plus.rb
44
+ - lib/mifare/ultralight.rb
45
+ - lib/mifare/ultralight_c.rb
40
46
  homepage: https://github.com/atitan/MFRC522_Ruby
41
47
  licenses:
42
48
  - MIT