main
 1# frozen_string_literal: true
 2
 3RSpec.describe ::Xml::Kit::Crypto::SymmetricCipher do
 4  %w[
 5    aes128-cbc
 6    aes192-cbc
 7    aes256-cbc
 8    tripledes-cbc
 9  ].each do |algorithm|
10    describe algorithm do
11      let(:xml_algorithm) { "#{::Xml::Kit::Namespaces::XMLENC}#{algorithm}" }
12      let(:openssl_algorithm) { Xml::Kit::Crypto::SymmetricCipher::ALGORITHMS[xml_algorithm].downcase }
13      let(:key) { SecureRandom.random_bytes(cipher.key_len) }
14      let(:iv) { SecureRandom.random_bytes(cipher.iv_len) }
15      let(:cipher) { OpenSSL::Cipher.new(openssl_algorithm) }
16
17      describe 'encrypting and decrypting' do
18        subject { described_class.new(xml_algorithm, key) }
19
20        let(:uuid) { SecureRandom.uuid }
21
22        specify { expect(subject.decrypt(subject.encrypt(uuid))).to eql(uuid) }
23      end
24
25      describe "decrypting #{algorithm} encrypted with the OpenSSL CLI" do
26        subject { described_class.new(xml_algorithm, key, 0) }
27
28        let(:encrypted_file) { Tempfile.new(algorithm).path }
29        let(:original_file) { Tempfile.new("#{algorithm}-original").path }
30        let(:secret) { SecureRandom.hex }
31        let(:data) { (iv.bytes + secret.bytes).pack('c*') }
32
33        context 'when encoded as ASCII' do
34          before do
35            IO.write(original_file, data, encoding: Encoding::ASCII_8BIT)
36            execute_shell([
37              "openssl enc -#{openssl_algorithm} -p -e -A -nosalt",
38              "-in #{original_file}",
39              "-out #{encrypted_file}",
40              "-K #{key.unpack1('H*').upcase}",
41              "-iv #{iv.unpack1('H*').upcase}"
42            ].join(' '))
43          end
44
45          specify do
46            cipher_text = IO.read(encrypted_file, encoding: Encoding::ASCII_8BIT)
47            expect(subject.decrypt(cipher_text)).to eql(secret)
48          end
49        end
50
51        context 'when encoded as UTF-8' do
52          before do
53            IO.write(original_file, data)
54            execute_shell([
55              "openssl enc -#{openssl_algorithm} -p -e -A -nosalt",
56              "-in #{original_file}",
57              "-out #{encrypted_file}",
58              "-K #{key.unpack1('H*').upcase}",
59              "-iv #{iv.unpack1('H*').upcase}"
60            ].join(' '))
61          end
62
63          specify do
64            cipher_text = IO.read(encrypted_file)
65            expect(subject.decrypt(cipher_text)).to eql(secret)
66          end
67        end
68      end
69
70      describe 'when decrypting with the OpenSSL CLI' do
71        subject { described_class.new(xml_algorithm, key) }
72
73        let(:encrypted_file) { Tempfile.new(algorithm).path }
74        let(:decrypted_file) { Tempfile.new("#{algorithm}-decrypted").path }
75        let(:secret) { SecureRandom.hex }
76
77        before do
78          IO.write(encrypted_file, subject.encrypt(secret))
79          execute_shell([
80            "openssl enc -#{openssl_algorithm} -p -d -nosalt",
81            "-in #{encrypted_file}",
82            "-out #{decrypted_file}",
83            "-K #{key.unpack1('H*').upcase}",
84            "-iv #{iv.unpack1('H*').upcase}"
85          ].join(' '))
86        end
87
88        specify { expect(IO.read(decrypted_file)).to end_with(secret) }
89      end
90    end
91  end
92end