module JWA::Algorithms::KeyManagement::AesKw

Generic AES Key Wrapping algorithm for any key size.

Attributes

iv[R]
key[R]

Public Class Methods

new(key, iv = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6") click to toggle source
# 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

Public Instance Methods

a_ri(b) click to toggle source
# 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
cipher() click to toggle source
# File lib/jwa/algorithms/key_management/aes_kw.rb, line 73
def cipher
  @cipher ||= Cipher.for(self.class.cipher_name)
end
decrypt(ciphertext) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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
kw_decrypt_round(j, a, r) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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