Module: Mifare::UltralightC

Defined in:
lib/mifare/ultralight_c.rb

Constant Summary collapse

CMD_3DES_AUTH =

Ultralight C 3DES Authentication.

0x1A

Instance Method Summary collapse

Instance Method Details

#auth(auth_key) ⇒ Object



5
6
7
8
9
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
# File 'lib/mifare/ultralight_c.rb', line 5

def auth(auth_key)
  if auth_key.cipher_suite != 'des-ede-cbc'
    raise UnexpectedDataError, 'Incorrect Auth Key Type'
  end

  auth_key.clear_iv

  # Ask for authentication
  buffer = [CMD_3DES_AUTH, 0x00]
  received_data = @pcd.picc_transceive(buffer)
  card_status = received_data.shift
  raise UnexpectedDataError, 'Incorrect response' if card_status != 0xAF

  challenge = auth_key.decrypt(received_data)
  challenge_rot = challenge.rotate

  # Generate 8 bytes random number and encrypt it with rotated challenge
  random_number = SecureRandom.random_bytes(8).bytes
  response = auth_key.encrypt(random_number + challenge_rot)

  # Send challenge response
  buffer = [0xAF] + response
  received_data = @pcd.picc_transceive(buffer)
  card_status = received_data.shift
  raise UnexpectedDataError, 'Incorrect response' if card_status != 0x00

  # Check if verification matches rotated random_number
  verification = auth_key.decrypt(received_data)

  if random_number.rotate != verification
    halt
    return @authed = false
  end

  @authed = true
end

#authed?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/mifare/ultralight_c.rb', line 42

def authed?
  @authed
end

#counter_increment(value) ⇒ Object



61
62
63
64
65
66
67
68
# File 'lib/mifare/ultralight_c.rb', line 61

def counter_increment(value)
  if value < 0
    raise UnexpectedDataError, 'Expect positive integer for counter'
  end
  # you can set any value between 0x0000 to 0xFFFF on the first write (initialize)
  # after initialized, counter can only be incremented by 0x01 ~ 0x0F
  write(0x29, [value & 0xFF, (value >> 8) & 0xFF, 0x00, 0x00])
end

#enable_protection_from(block_addr) ⇒ Object



70
71
72
73
74
75
76
77
78
# File 'lib/mifare/ultralight_c.rb', line 70

def enable_protection_from(block_addr)
  if block_addr >= 0x03 && block_addr <= 0x30
    raise UnexpectedDataError, 'Requested block beyond memory limit'
  end
  # authentication will be required from `block_addr` to 0x2F
  # valid value are from 0x03 to 0x30
  # set to 0x30 to disable memory protection
  write(0x2A, [block_addr & 0x3F, 0x00, 0x00, 0x00])
end

#set_protection_type(type) ⇒ Object



80
81
82
83
84
# File 'lib/mifare/ultralight_c.rb', line 80

def set_protection_type(type)
  # set to 0 for read-write access restriction (default)
  # set to 1 for write access restriction
  write(0x2B, [type & 0x01, 0x00, 0x00, 0x00])
end

#write_des_key(key) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/mifare/ultralight_c.rb', line 46

def write_des_key(key)
  # key should be 16 bytes long
  bytes = [key].pack('H*').bytes
  if bytes.size != 16
    raise UnexpectedDataError, "Expect 16 bytes 3DES key, got: #{bytes.size} byte"
  end

  # Key1
  write(0x2C, bytes[4..7].reverse)
  write(0x2D, bytes[0..3].reverse)
  # Key2
  write(0x2E, bytes[12..15].reverse)
  write(0x2F, bytes[8..11].reverse)
end