Class: Mifare::Key

Inherits:
Object
  • Object
show all
Defined in:
lib/mifare/key.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, key, version = 0x00) ⇒ Key

Returns a new instance of Key.



8
9
10
11
12
13
# File 'lib/mifare/key.rb', line 8

def initialize(type, key, version = 0x00)
  @type = type
  set_key_data(type, key, version)
  clear_iv
  init_cipher
end

Instance Attribute Details

#cipher_suiteObject (readonly)

Returns the value of attribute cipher_suite.



4
5
6
# File 'lib/mifare/key.rb', line 4

def cipher_suite
  @cipher_suite
end

#key_sizeObject (readonly)

Returns the value of attribute key_size.



5
6
7
# File 'lib/mifare/key.rb', line 5

def key_size
  @key_size
end

#typeObject (readonly)

Returns the value of attribute type.



3
4
5
# File 'lib/mifare/key.rb', line 3

def type
  @type
end

#versionObject (readonly)

Returns the value of attribute version.



6
7
8
# File 'lib/mifare/key.rb', line 6

def version
  @version
end

Instance Method Details

#calculate_cmac(data) ⇒ Object



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
# File 'lib/mifare/key.rb', line 54

def calculate_cmac(data)
  if @cmac_subkey1.nil? || @cmac_subkey2.nil?
    raise 'Generate subkeys before calculating CMAC'
  end

  # Separate from input object
  data = data.dup

  if data.size == 0 || data.size % @block_size != 0
    # padding with byte: 0x80, 0x00, 0x00.....
    data << 0x80
    until data.size % @block_size == 0
      data << 0x00
    end

    key = @cmac_subkey2
  else
    key = @cmac_subkey1
  end

  # XOR last data block with selected CMAC subkey
  data = data[0...-@block_size] + data[-@block_size..-1].zip(key).map{|x, y| x ^ y }
  encrypt(data)

  @cipher_iv.bytes
end

#clear_ivObject



36
37
38
# File 'lib/mifare/key.rb', line 36

def clear_iv
  @cipher_iv = "\x00" * @block_size
end

#decrypt(data, cbc_mode = :receive) ⇒ Object



30
31
32
33
34
# File 'lib/mifare/key.rb', line 30

def decrypt(data, cbc_mode = :receive)
  @cipher.decrypt

  cbc_crypt(data, cbc_mode)
end

#encrypt(data, cbc_mode = :send) ⇒ Object



19
20
21
22
23
24
25
26
27
28
# File 'lib/mifare/key.rb', line 19

def encrypt(data, cbc_mode = :send)
  @cipher.encrypt

  # Add padding if not a complete block
  until data.size % @block_size == 0
    data << 0x00
  end
  
  cbc_crypt(data, cbc_mode)
end

#generate_cmac_subkeysObject



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/mifare/key.rb', line 40

def generate_cmac_subkeys
  r = (@block_size == 8) ? 0x1B : 0x87
  data = Array.new(@block_size, 0)

  clear_iv
  data = encrypt(data, :receive)

  @cmac_subkey1 = bit_shift_left(data)
  @cmac_subkey1[-1] ^= r if data[0] & 0x80 != 0

  @cmac_subkey2 = bit_shift_left(@cmac_subkey1)
  @cmac_subkey2[-1] ^= r if @cmac_subkey1[0] & 0x80 != 0
end

#keyObject



15
16
17
# File 'lib/mifare/key.rb', line 15

def key
  @key.bytes
end