Module: JWA::Algorithms::KeyManagement::AesKw

Included in:
A128Kw, A192Kw, A256Kw
Defined in:
lib/jwa/algorithms/key_management/aes_kw.rb

Overview

Generic AES Key Wrapping algorithm for any key size.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#ivObject (readonly)

Returns the value of attribute iv.



8
9
10
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 8

def iv
  @iv
end

#keyObject (readonly)

Returns the value of attribute key.



8
9
10
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 8

def key
  @key
end

Instance Method Details

#a_ri(b) ⇒ Object



69
70
71
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 69

def a_ri(b)
  [b.first(8).join, b.to_a.last(8).join]
end

#cipherObject



73
74
75
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 73

def cipher
  @cipher ||= Cipher.for(self.class.cipher_name)
end

#decrypt(ciphertext) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 42

def decrypt(ciphertext)
  c = ciphertext.force_encoding('ASCII-8BIT').scan(/.{8}/m)
  a, *r = c

  5.downto(0) do |j|
    a, r = kw_decrypt_round(j, a, r)
  end

  if a != @iv
    raise StandardError, 'The encrypted key has been tampered. Do not use this key.'
  end

  r.join
end

#decrypt_round(data) ⇒ Object



84
85
86
87
88
89
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 84

def decrypt_round(data)
  cipher.decrypt
  cipher.key = @key
  cipher.padding = 0
  cipher.update(data) + cipher.final
end

#encrypt(plaintext) ⇒ Object



19
20
21
22
23
24
25
26
27
28
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 19

def encrypt(plaintext)
  a = @iv
  r = plaintext.force_encoding('ASCII-8BIT').scan(/.{8}/m)

  6.times do |j|
    a, r = kw_encrypt_round(j, a, r)
  end

  ([a] + r).join
end

#encrypt_round(data) ⇒ Object



77
78
79
80
81
82
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 77

def encrypt_round(data)
  cipher.encrypt
  cipher.key = @key
  cipher.padding = 0
  cipher.update(data) + cipher.final
end

#initialize(key, iv = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6") ⇒ Object



10
11
12
13
14
15
16
17
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 10

def initialize(key, iv = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6")
  @key = key.force_encoding('ASCII-8BIT')
  @iv = iv.force_encoding('ASCII-8BIT')

  if @key.length != self.class.key_length
    raise ArgumentError, "Invalid Key. Expected length: #{self.class.key_length}. Actual: #{@key.length}."
  end
end

#kw_decrypt_round(j, a, r) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 57

def kw_decrypt_round(j, a, r)
  r.length.downto(1) do |i|
    a = xor(a, (r.length * j) + i)

    b = decrypt_round(a + r[i - 1]).chars

    a, r[i - 1] = a_ri(b)
  end

  [a, r]
end

#kw_encrypt_round(j, a, r) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 30

def kw_encrypt_round(j, a, r)
  r.length.times do |i|
    b = encrypt_round(a + r[i]).chars

    a, r[i] = a_ri(b)

    a = xor(a, (r.length * j) + i + 1)
  end

  [a, r]
end

#xor(data, t) ⇒ Object



91
92
93
94
95
96
# File 'lib/jwa/algorithms/key_management/aes_kw.rb', line 91

def xor(data, t)
  t = ([0] * (data.length - 1)) + [t]
  data = data.chars.map(&:ord)

  data.zip(t).map { |a, b| (a ^ b).chr }.join
end