main
 1# frozen_string_literal: true
 2
 3module Xml
 4  module Kit
 5    module Crypto
 6      class SymmetricCipher
 7        DEFAULT_ALGORITHM = "#{::Xml::Kit::Namespaces::XMLENC}aes256-cbc"
 8        ALGORITHMS = {
 9          "#{::Xml::Kit::Namespaces::XMLENC}tripledes-cbc" => 'DES-EDE3-CBC',
10          "#{::Xml::Kit::Namespaces::XMLENC}aes128-cbc" => 'AES-128-CBC',
11          "#{::Xml::Kit::Namespaces::XMLENC}aes192-cbc" => 'AES-192-CBC',
12          "#{::Xml::Kit::Namespaces::XMLENC}aes256-cbc" => 'AES-256-CBC',
13        }.freeze
14
15        attr_reader :algorithm, :key, :padding
16
17        def initialize(algorithm = DEFAULT_ALGORITHM, key = nil, padding = nil)
18          @algorithm = algorithm
19          @key = key || cipher.random_key
20          @padding = padding
21        end
22
23        def self.matches?(algorithm)
24          ALGORITHMS[algorithm]
25        end
26
27        def encrypt(plain_text)
28          cipher.encrypt
29          cipher.key = @key
30          cipher.random_iv + cipher.update(plain_text) + cipher.final
31        end
32
33        def decrypt(cipher_text)
34          bytes = cipher_text.bytes
35          result = default_decrypt(
36            bytes[0...cipher.iv_len],
37            bytes[cipher.iv_len..-1]
38          )
39          return result if padding.nil?
40
41          padding_size = result.bytes.last
42          result[0...-padding_size]
43        end
44
45        def to_s
46          algorithm
47        end
48
49        protected
50
51        def default_decrypt(initialization_vector, data)
52          cipher.decrypt
53          apply_padding_to(cipher)
54          cipher.key = @key
55          cipher.iv = initialization_vector.pack('c*')
56          cipher.update(data.pack('c*')) << cipher.final
57        end
58
59        private
60
61        def cipher
62          @cipher ||= OpenSSL::Cipher.new(ALGORITHMS[algorithm])
63        end
64
65        def apply_padding_to(cipher)
66          cipher.padding = padding unless padding.nil?
67        end
68      end
69    end
70  end
71end