lib/jwe/enc/aes_cbc_hs.rb in jwe-0.3.0 vs lib/jwe/enc/aes_cbc_hs.rb in jwe-0.3.1
- old
+ new
@@ -1,7 +1,10 @@
+require 'jwe/enc/cipher'
+
module JWE
module Enc
+ # Abstract AES in Block cipher mode, with message signature for different key sizes.
module AesCbcHs
attr_accessor :cek
attr_accessor :iv
attr_accessor :tag
@@ -11,43 +14,47 @@
end
def encrypt(cleartext, authenticated_data)
raise JWE::BadCEK.new("The supplied key is invalid. Required length: #{key_length}") if cek.length != key_length
- cipher.encrypt
- cipher.key = enc_key
- cipher.iv = iv
+ ciphertext = cipher_round(:encrypt, iv, cleartext)
- ciphertext = cipher.update(cleartext) + cipher.final
- length = [authenticated_data.length * 8].pack('Q>') # 64bit big endian
+ signature = generate_tag(authenticated_data, iv, ciphertext)
+ self.tag = signature
- to_sign = authenticated_data + iv + ciphertext + length
- signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new(hash_name), mac_key, to_sign)
- self.tag = signature[0...mac_key.length]
-
ciphertext
end
def decrypt(ciphertext, authenticated_data)
- raise JWE::BadCEK.new("The supplied key is invalid. Required length: #{key_length}") if cek.length != key_length
+ raise JWE::BadCEK, "The supplied key is invalid. Required length: #{key_length}" if cek.length != key_length
- length = [authenticated_data.length * 8].pack('Q>') # 64bit big endian
- to_sign = authenticated_data + iv + ciphertext + length
- signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new(hash_name), mac_key, to_sign)
- if signature[0...mac_key.length] != tag
- raise JWE::InvalidData.new('Authentication tag verification failed')
+ signature = generate_tag(authenticated_data, iv, ciphertext)
+ if signature != tag
+ raise JWE::InvalidData, 'Authentication tag verification failed'
end
- cipher.decrypt
+ cipher_round(:decrypt, iv, ciphertext)
+ rescue OpenSSL::Cipher::CipherError
+ raise JWE::InvalidData, 'Invalid ciphertext or authentication tag'
+ end
+
+ def cipher_round(direction, iv, data)
+ cipher.send(direction)
cipher.key = enc_key
cipher.iv = iv
- cipher.update(ciphertext) + cipher.final
- rescue OpenSSL::Cipher::CipherError
- raise JWE::InvalidData.new('Invalid ciphertext or authentication tag')
+ cipher.update(data) + cipher.final
end
+ def generate_tag(authenticated_data, iv, ciphertext)
+ length = [authenticated_data.length * 8].pack('Q>') # 64bit big endian
+ to_sign = authenticated_data + iv + ciphertext + length
+ signature = OpenSSL::HMAC.digest(OpenSSL::Digest.new(hash_name), mac_key, to_sign)
+
+ signature[0...mac_key.length]
+ end
+
def iv
@iv ||= SecureRandom.random_bytes(16)
end
def cek
@@ -61,22 +68,21 @@
def enc_key
cek[key_length / 2..-1]
end
def cipher
- @cipher ||= OpenSSL::Cipher.new(cipher_name)
- rescue RuntimeError
- raise JWE::NotImplementedError.new("The version of OpenSSL linked to your Ruby does not support the cipher #{cipher_name}.")
+ @cipher ||= Cipher.for(cipher_name)
end
def tag
@tag || ''
end
def self.included(base)
base.extend(ClassMethods)
end
+ # Provides availability checks for Key Encryption algorithms
module ClassMethods
def available?
new.cipher
true
rescue JWE::NotImplementedError