mfrc522 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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