Commit 8ef2adf

mokha <mo@mokhan.ca>
2018-11-24 19:34:15
provide extension for custom encryption algorithms.
This change allows client to provide their own custom Symmetric and/or Asymmetric encryption algorithms to encrypt data. ```ruby class MySymmetric def key Digest::SHA256.digest('secret') end def encrypt(data) # ... end def to_s "http://www.w3.org/2001/04/xmlenc#my-algorithm" end end class MyAsymmetric def encrypt(data) # ... end def to_s "http://www.w3.org/2001/04/xmlenc#my-algorithm" end end symmetric_algorithm = MySymmetric.new asymmetric_algorithm = MyAsymmetric.new encryption = Xml::Kit::Encryption.new( xml, public_key, symmetric_algorithm: symmetric_algorithm, asymmetric_algorithm: asymmetric_algorithm ) ```
1 parent 3472906
lib/xml/kit/encryption.rb
@@ -15,11 +15,16 @@ module Xml
         asymmetric_algorithm: ::Xml::Kit::Crypto::RsaCipher::ALGORITHM
       )
         @symmetric_algorithm = symmetric_algorithm
-        @symmetric_cipher_value = Base64.encode64(symmetric_cipher.encrypt(raw_xml)).delete("\n")
+        symmetric_cipher = symmetric(symmetric_algorithm)
+        @symmetric_cipher_value = Base64.strict_encode64(
+          symmetric_cipher.encrypt(raw_xml)
+        )
 
         @asymmetric_algorithm = asymmetric_algorithm
-        cipher = Crypto.cipher_for(asymmetric_algorithm, public_key)
-        @asymmetric_cipher_value = Base64.encode64(cipher.encrypt(symmetric_cipher.key)).delete("\n")
+        asymmetric_cipher = asymmetric(asymmetric_algorithm, public_key)
+        @asymmetric_cipher_value = Base64.strict_encode64(
+          asymmetric_cipher.encrypt(symmetric_cipher.key)
+        )
       end
 
       def to_xml(xml: ::Builder::XmlMarkup.new)
@@ -28,10 +33,16 @@ module Xml
 
       private
 
-      def symmetric_cipher
-        @symmetric_cipher ||= ::Xml::Kit::Crypto::SymmetricCipher.new(
-          symmetric_algorithm
-        )
+      def symmetric(algorithm)
+        return algorithm unless algorithm.is_a?(String)
+
+        ::Xml::Kit::Crypto::SymmetricCipher.new(algorithm)
+      end
+
+      def asymmetric(algorithm, public_key)
+        return algorithm unless algorithm.is_a?(String)
+
+        ::Xml::Kit::Crypto.cipher_for(algorithm, public_key)
       end
     end
   end
lib/xml/kit/version.rb
@@ -2,6 +2,6 @@
 
 module Xml
   module Kit
-    VERSION = '0.1.14'.freeze
+    VERSION = '0.1.15'.freeze
   end
 end
spec/xml/kit/crypto/symmetric_cipher_spec.rb
@@ -12,10 +12,10 @@ RSpec.describe ::Xml::Kit::Crypto::SymmetricCipher do
 
       let(:key) { SecureRandom.hex(key_size[algorithm]) }
       let(:key_size) do
-        hash = Hash.new(32/2)
-        hash['aes128-cbc'] = 16/2
-        hash['aes192-cbc'] = 24/2
-        hash['tripledes-cbc'] = 24/2
+        hash = Hash.new(32 / 2)
+        hash['aes128-cbc'] = 16 / 2
+        hash['aes192-cbc'] = 24 / 2
+        hash['tripledes-cbc'] = 24 / 2
         hash
       end
       let(:uuid) { SecureRandom.uuid }
spec/xml/kit/encryption_spec.rb
@@ -32,5 +32,29 @@ RSpec.describe Xml::Kit::Encryption do
         end
       end
     end
+
+    describe 'custom ciphers' do
+      subject { described_class.new(xml, public_key, symmetric_algorithm: symmetric_cipher, asymmetric_algorithm: asymmetric_cipher) }
+
+      let(:symmetric_cipher) { instance_double(Xml::Kit::Crypto::SymmetricCipher, key: 'symmetric_key', encrypt: 'CIPHERTEXT', to_s: 'symmetric_cipher') }
+      let(:asymmetric_cipher) { instance_double(Xml::Kit::Crypto::RsaCipher, encrypt: 'asymmetric CIPHERTEXT', to_s: 'asymmetric_cipher') }
+      let(:key_pair) { Xml::Kit::KeyPair.generate(use: :encryption) }
+      let(:public_key) { key_pair.public_key }
+      let(:xml) do
+        xml = ::Builder::XmlMarkup.new
+        xml.HellWorld do
+          xml.Now Time.now.iso8601
+        end
+        xml.target!
+      end
+      let(:result) { Hash.from_xml(subject.to_xml) }
+
+      specify { expect(result['EncryptedData']).to be_present }
+      specify { expect(result['EncryptedData']['EncryptionMethod']['Algorithm']).to eql('symmetric_cipher') }
+      specify { expect(result['EncryptedData']['KeyInfo']).to be_present }
+      specify { expect(result['EncryptedData']['KeyInfo']['EncryptedKey']['EncryptionMethod']['Algorithm']).to eql('asymmetric_cipher') }
+      specify { expect(result['EncryptedData']['KeyInfo']['EncryptedKey']['CipherData']['CipherValue']).to eql(Base64.strict_encode64('asymmetric CIPHERTEXT')) }
+      specify { expect(result['EncryptedData']['CipherData']['CipherValue']).to eql(Base64.strict_encode64('CIPHERTEXT')) }
+    end
   end
 end