Class: Milenage::Kernel

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

Overview

The core class for calculating Milenage security functions.

To use this class, determine the operator variant algorithm configuration field (OP) or the pre-encrypted version of the same (OPc) and also determine the user-specific key value (KEY). Create an instance of the kernel class, passing the key, then set the OP/OPc as needed:

m = Milenage::Kernel.new(KEY)
m.op = OP # or m.opc = OPc

At this point, the kernel instance can be used to calculate security functions for the user:

mac_a = m.f1(RAND, SQN, AMF)
mac_s = m.f1_star(RAND, SQN, AMF)
res = m.f2(RAND)
ck = m.f3(RAND)
ik = m.f4(RAND)
ak = m.r5(RAND) # or ak = m.f5_star(RAND)

You may change the OP/OPc at any time if needed:

m.op = NEW_OP
m.opc = NEW_OPc

Instance Method Summary collapse

Constructor Details

#initialize(key) ⇒ Kernel

Create a single user’s kernel instance, remember to set OP or OPc before attempting to use the security functions.

To change the algorithm variables as described in TS 35.206 subclass this Kernel class and modify ‘@c`, `@r` or `@kernel` after calling super. E.G.

class MyKernel < Kernel
  def initialize(key)
    super
    @r = [10, 20, 30, 40, 50]
  end
end

When doing this, ‘@kernel` should be set to a 128-bit MAC function with the same API as `OpenSSL::Cipher`, if this is not the case, you may need to overload #enc as well to match the API.



47
48
49
50
51
52
53
# File 'lib/milenage.rb', line 47

def initialize(key)
  fail "KEY must be 128 bits" unless key.each_byte.to_a.length == 16
  @key = key
  @c = [0, 1, 2, 4, 8].map { |i| [0, i].pack("Q>2") }
  @r = [64, 0, 32, 64, 96]
  @kernel = OpenSSL::Cipher::AES128.new(:ECB)
end

Instance Method Details

#f1(rand, sqn, amf) ⇒ Object

Calculate the network authentication code (MAC-A)



82
83
84
# File 'lib/milenage.rb', line 82

def f1(rand, sqn, amf)
  step_a(rand, sqn, amf)[0..7]
end

#f1_star(rand, sqn, amf) ⇒ Object

Calculate the resync authentication code (MAC-S)



87
88
89
# File 'lib/milenage.rb', line 87

def f1_star(rand, sqn, amf)
  step_a(rand, sqn, amf)[8..15]
end

#f2(rand) ⇒ Object

Calculate the response (RES)



92
93
94
# File 'lib/milenage.rb', line 92

def f2(rand)
  step_b(rand)[8..15]
end

#f3(rand) ⇒ Object

Calculate the confidentiallity key (CK)



97
98
99
# File 'lib/milenage.rb', line 97

def f3(rand)
  step_c(rand)
end

#f4(rand) ⇒ Object

Calculate the integrity key (IK)



102
103
104
# File 'lib/milenage.rb', line 102

def f4(rand)
  step_d(rand)
end

#f5(rand) ⇒ Object

Calculate the anonymity key (AK)



107
108
109
# File 'lib/milenage.rb', line 107

def f5(rand)
  step_b(rand)[0..5]
end

#f5_star(rand) ⇒ Object

Calculate the anonymity resynch key (AK)



112
113
114
# File 'lib/milenage.rb', line 112

def f5_star(rand)
  step_e(rand)[0..5]
end

#op=(op) ⇒ Object

Set the Operator Variant Algorithm Configuration field.

Either this or #opc= must be called before any of the security functions are evaluated.



59
60
61
62
# File 'lib/milenage.rb', line 59

def op=(op)
  fail "OP must be 128 bits" unless op.each_byte.to_a.length == 16
  @opc = xor(enc(op), op)
end

#opcObject

Standard getter for the OPc.



76
77
78
79
# File 'lib/milenage.rb', line 76

def opc
  fail "Must set OP or OPc before retrieving OPc" unless @opc
  @opc
end

#opc=(opc) ⇒ Object

Set the precomputed encoded Operator Variant Algorithm Configuration field. Note that there are no checks that this value is even feasible for the given key.

Either this or #op= must be called before any of the security functions are evaluated.



70
71
72
73
# File 'lib/milenage.rb', line 70

def opc=(opc)
  fail "OPc must be 128 bits" unless opc.each_byte.to_a.length == 16
  @opc = opc
end