module JWA::Algorithms::ContentEncryption::AesCbcHs

Abstract AES in CBC mode, with SHA2 signature for different key sizes.

Attributes

iv[R]
key[R]

Public Class Methods

included(base) click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 70
def self.included(base)
  base.extend(ClassMethods)
end
new(key, iv = nil) click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 10
def initialize(key, iv = nil)
  @key = key
  @iv = iv || SecureRandom.random_bytes(16)

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

  if @iv.length != 16
    raise ArgumentError, "Invalid IV. Expected length: 16. Actual: #{@iv.length}."
  end
end

Public Instance Methods

cipher() click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 66
def cipher
  @cipher ||= Cipher.for(self.class.cipher_name)
end
cipher_round(direction, data) click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 41
def cipher_round(direction, data)
  cipher.send(direction)
  cipher.key = enc_key
  cipher.iv = @iv

  cipher.update(data) + cipher.final
end
decrypt(ciphertext, authenticated_data, tag) click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 30
def decrypt(ciphertext, authenticated_data, tag)
  signature = generate_tag(authenticated_data, ciphertext)
  if signature != tag
    raise JWA::BadDecrypt, 'Signature check failed. The AAD may have been tampered.'
  end

  cipher_round(:decrypt, ciphertext)
rescue OpenSSL::Cipher::CipherError
  raise JWA::BadDecrypt, 'Invalid ciphertext or authentication tag.'
end
enc_key() click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 62
def enc_key
  @key[self.class.key_length / 2..-1]
end
encrypt(plaintext, authenticated_data) click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 23
def encrypt(plaintext, authenticated_data)
  ciphertext = cipher_round(:encrypt, plaintext)
  signature = generate_tag(authenticated_data, ciphertext)

  [ciphertext, signature]
end
generate_tag(authenticated_data, ciphertext) click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 49
def generate_tag(authenticated_data, ciphertext)
  length = [authenticated_data.length * 8].pack('Q>') # 64bit big endian

  to_sign = authenticated_data + @iv + ciphertext + length
  signature = OpenSSL::HMAC.digest(self.class.hash, mac_key, to_sign)

  signature[0...mac_key.length]
end
mac_key() click to toggle source
# File lib/jwa/algorithms/content_encryption/aes_cbc_hs.rb, line 58
def mac_key
  @key[0...self.class.key_length / 2]
end