ripple-encryption 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ *.swp
3
+ coverage
data/Gemfile CHANGED
@@ -1,13 +1,12 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in ripple-contrib.gemspec
4
3
  gemspec
5
4
 
6
5
  gem 'riak-client', '~> 1.1.1'
7
6
  gem 'ripple', :git => 'git://github.com/basho/ripple.git', :ref => '913806aa2942db5a3b61d1432d2c9be200338f50'
8
7
 
9
8
  group :development, :test do
10
- gem 'linecache19', :git => 'git://github.com/mark-moseley/linecache'
11
- gem 'ruby-debug-base19x', '~> 0.11.30.pre4'
12
- gem "ruby-debug19", "0.11.6"
9
+ gem 'ruby-prof'
10
+ gem 'simplecov'
11
+ gem 'debugger'
13
12
  end
@@ -9,17 +9,11 @@ GIT
9
9
  riak-client (~> 1.1.0)
10
10
  tzinfo
11
11
 
12
- GIT
13
- remote: git://github.com/mark-moseley/linecache
14
- revision: 869c6a65155068415925067e480741bd0a71527e
15
- specs:
16
- linecache19 (0.5.12)
17
- ruby_core_source (>= 0.1.4)
18
-
19
12
  PATH
20
13
  remote: .
21
14
  specs:
22
- ripple-encryption (0.0.3)
15
+ ripple-encryption (0.0.4)
16
+ rake
23
17
  riak-client
24
18
  ripple
25
19
 
@@ -32,49 +26,43 @@ GEM
32
26
  activesupport (3.2.12)
33
27
  i18n (~> 0.6)
34
28
  multi_json (~> 1.0)
35
- archive-tar-minitar (0.5.2)
36
29
  beefcake (0.3.7)
37
30
  builder (3.0.4)
38
31
  columnize (0.3.6)
32
+ debugger (1.6.0)
33
+ columnize (>= 0.3.1)
34
+ debugger-linecache (~> 1.2.0)
35
+ debugger-ruby_core_source (~> 1.2.1)
36
+ debugger-linecache (1.2.0)
37
+ debugger-ruby_core_source (1.2.2)
39
38
  i18n (0.6.4)
40
39
  innertube (1.0.2)
41
40
  mini_shoulda (0.5.0)
42
41
  minitest (> 2.1.0)
43
42
  minitest (3.3.0)
44
43
  multi_json (1.6.1)
45
- rake (0.9.2.2)
44
+ rake (10.0.3)
46
45
  riak-client (1.1.1)
47
46
  beefcake (~> 0.3.7)
48
47
  builder (>= 2.1.2)
49
48
  i18n (>= 0.4.0)
50
49
  innertube (~> 1.0.2)
51
50
  multi_json (~> 1.0)
52
- ruby-debug-base19 (0.11.25)
53
- columnize (>= 0.3.1)
54
- linecache19 (>= 0.5.11)
55
- ruby_core_source (>= 0.1.4)
56
- ruby-debug-base19x (0.11.30.pre10)
57
- columnize (>= 0.3.1)
58
- linecache19 (>= 0.5.11)
59
- rake (>= 0.8.1)
60
- ruby_core_source (>= 0.1.4)
61
- ruby-debug19 (0.11.6)
62
- columnize (>= 0.3.1)
63
- linecache19 (>= 0.5.11)
64
- ruby-debug-base19 (>= 0.11.19)
65
- ruby_core_source (0.1.5)
66
- archive-tar-minitar (>= 0.5.2)
51
+ ruby-prof (0.12.1)
52
+ simplecov (0.7.1)
53
+ multi_json (~> 1.0)
54
+ simplecov-html (~> 0.7.1)
55
+ simplecov-html (0.7.1)
67
56
  tzinfo (0.3.35)
68
57
 
69
58
  PLATFORMS
70
59
  ruby
71
60
 
72
61
  DEPENDENCIES
73
- linecache19!
62
+ debugger
74
63
  mini_shoulda
75
- rake
76
64
  riak-client (~> 1.1.1)
77
65
  ripple!
78
66
  ripple-encryption!
79
- ruby-debug-base19x (~> 0.11.30.pre4)
80
- ruby-debug19 (= 0.11.6)
67
+ ruby-prof
68
+ simplecov
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Ripple::Encryption
2
2
 
3
- The ripple-encryption gem provides encryption and decryption for Ripple documents.
4
- [riak-ruby](https://github.com/basho/riak-ruby-client) [ripple](https://github.com/basho/ripple)
3
+ The ripple-encryption gem provides encryption and decryption for Ripple documents. This gem's primary dependencies are [riak-ruby](https://github.com/basho/riak-ruby-client) and [ripple](https://github.com/basho/ripple).
5
4
 
6
5
 
7
6
  ## Installation
@@ -29,7 +28,8 @@ which makes the actual calls to OpenSSL.
29
28
 
30
29
  JsonDocument stores the encrypted data wrapped in JSON encapsulation so
31
30
  that you can still introspect the Riak object and see which version of
32
- this gem was used to encrypt it.
31
+ this gem was used to encrypt it. As of version 0.0.4, this is now the only
32
+ supported serialization format for JSON data.
33
33
 
34
34
  There is also a Rake file to convert between encrypted and decrypted
35
35
  JSON objects.
@@ -58,6 +58,21 @@ Adjust the 'test/fixtures/ripple.yml' to point to a test riak database.
58
58
 
59
59
  bundle exec rake
60
60
 
61
+ ## Compatibility Matrix
62
+
63
+ This gem stores serialized encryption objects into Riak. The serialization
64
+ format is versioned; and where possible incrementally transitioned from one
65
+ version to another. Currently; only the ```JsonSerializer``` supports this
66
+ type of incremental transition with the support matrix below.
67
+
68
+ | version | First | Last |
69
+ | -------- | ----- | ------- |
70
+ | v1 | 0.0.1 | 0.0.3 |
71
+ | v2 | 0.0.2 | current |
72
+
73
+ The ```BinarySerializer``` does not support incremental format transition but
74
+ does make the version and iv available for external code to support this.
75
+
61
76
  ## Contributing
62
77
 
63
78
  1. Fork it
@@ -8,3 +8,4 @@ end
8
8
 
9
9
  # Include all of the support files.
10
10
  FileList[File.expand_path(File.join('..','ripple-encryption','*.rb'),__FILE__)].each{|f| require f}
11
+ FileList[File.expand_path(File.join('..','ripple-encryption/types','*.rb'),__FILE__)].each{|f| require f}
@@ -8,68 +8,71 @@ module Ripple
8
8
  # serialized form before it is stored in Riak. You must register
9
9
  # a serializer that will perform the encryption.
10
10
  # @see Serializer
11
- extend ActiveSupport::Concern
11
+ extend ActiveSupport::Concern
12
12
 
13
- @@is_activated = false
13
+ @@is_activated = false
14
14
 
15
- included do
16
- @@encrypted_content_type = self.encrypted_content_type = 'application/x-json-encrypted'
17
- end
15
+ included do
16
+ # This sets the default encrypted serializer to JSON
17
+ # (ActiveSupport friendly at the cost of more bytes)
18
+ @@encrypted_content_type = self.encrypted_content_type = Ripple::Encryption::JsonSerializer::REGISTER_KEY
19
+ end
18
20
 
19
- module ClassMethods
20
- # @return [String] the content type to be used to indicate the
21
- # proper encryption scheme. Defaults to 'application/x-json-encrypted'
22
- attr_accessor :encrypted_content_type
23
- end
21
+ module ClassMethods
22
+ # @return [String] the content type to be used to indicate the
23
+ # proper encryption scheme. Defaults to 'application/x-json-encrypted'
24
+ attr_accessor :encrypted_content_type
25
+ end
24
26
 
25
- # Overrides the internal method to set the content-type to be
26
- # encrypted.
27
- def update_robject
28
- super
29
- if @@is_activated
30
- robject.content_type = @@encrypted_content_type
31
- end
32
- end
27
+ # Overrides the internal method to set the content-type to be
28
+ # encrypted using the default encrypted serializer.
29
+ def update_robject
30
+ super
31
+ robject.content_type = @@encrypted_content_type if Ripple::Encryption.activated?
32
+ end
33
33
 
34
- def self.activate(path)
35
- encryptor = nil
36
- unless Riak::Serializers['application/x-json-encrypted']
37
- begin
38
- config = YAML.load_file(path)[ENV['RACK_ENV']]
39
- encryptor = Ripple::Encryption::Serializer.new(OpenSSL::Cipher.new(config['cipher']), 'application/x-json-encrypted', path)
40
- rescue Exception => e
41
- handle_invalid_encryption_config(e.message, e.backtrace)
42
- end
43
- encryptor.key = config['key'] if config['key']
44
- encryptor.iv = config['iv'] if config['iv']
45
- Riak::Serializers['application/x-json-encrypted'] = encryptor
46
- @@is_activated = true
47
- end
48
- encryptor
34
+ def self.activate(path)
35
+ primary_encryptor = nil
36
+ [Ripple::Encryption::JsonSerializer, Ripple::Encryption::BinarySerializer].each do |serializer|
37
+ encryptor = self.load_serializer(serializer, path)
38
+ primary_encryptor if serializer == Ripple::Encryption::JsonSerializer
49
39
  end
40
+ primary_encryptor
41
+ end
42
+
43
+ def self.activated?
44
+ @@is_activated
45
+ end
46
+
47
+ private
50
48
 
51
- def self.activated
52
- @@is_activated
49
+ def self.load_serializer(serializer_class, path)
50
+ begin
51
+ config = YAML.load_file(path)[ENV['RACK_ENV']]
52
+ encryptor = serializer_class.new(OpenSSL::Cipher.new(config['cipher']), path)
53
+ rescue Exception => e
54
+ handle_invalid_encryption_config(e)
55
+ ensure
56
+ @@is_activated = false
53
57
  end
58
+ encryptor.key = config['key'] if config['key']
59
+ encryptor.iv = config['iv'] if config['iv']
60
+ Riak::Serializers[serializer_class::REGISTER_KEY] = encryptor
61
+ @@is_activated = true
62
+ encryptor
63
+ end
54
64
 
55
65
  end
56
66
  end
57
67
 
58
- def handle_invalid_encryption_config(msg, trace)
59
- puts <<eos
68
+ def handle_invalid_encryption_config(exception)
69
+ raise Ripple::Encryption::ConfigError, <<eos
60
70
 
61
71
  The file "config/encryption.yml" is missing or incorrect. You will
62
72
  need to create this file and populate it with a valid cipher,
63
73
  initialization vector and secret key.
64
74
 
65
75
  An example is provided in "config/encryption.yml.example".
66
- eos
67
-
68
- puts "Error Message: " + msg
69
- puts "Error Trace:"
70
- trace.each do |line|
71
- puts line
72
- end
73
76
 
74
- exit 1
77
+ eos
75
78
  end
@@ -2,9 +2,6 @@ require 'openssl'
2
2
 
3
3
  module Ripple
4
4
  module Encryption
5
- # Generic error class for Config
6
- class ConfigError < StandardError; end
7
-
8
5
  # Handles the configuration information for the Encryptor.
9
6
  #
10
7
  # Example usage:
@@ -24,8 +21,8 @@ module Ripple
24
21
  end
25
22
 
26
23
  # Return either the default initialization vector, or create a new one.
27
- def activate
28
- @config['iv'] ||= OpenSSL::Random.random_bytes(16)
24
+ def generate_new_iv
25
+ @config['iv'] = OpenSSL::Random.random_bytes(16)
29
26
  end
30
27
 
31
28
  def validate_path(path)
@@ -1,8 +1,5 @@
1
1
  module Ripple
2
2
  module Encryption
3
- # Generic error class for Encryptor
4
- class EncryptorConfigError < StandardError; end
5
-
6
3
  # Implements a simple object that can either encrypt or decrypt arbitrary data.
7
4
  #
8
5
  # Example usage:
@@ -0,0 +1,12 @@
1
+ module Ripple
2
+ module Encryption
3
+ # reserved for general config lookup errors
4
+ class ConfigError < StandardError; end
5
+
6
+ # reserved for specific encryptor (openssl) config related errors
7
+ class EncryptorConfigError < StandardError; end
8
+
9
+ # reserved for issues decrypting & deserializing JSON
10
+ class EncryptedJsonDocumentError < StandardError; end
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ module Ripple
2
+ module Encryption
3
+ # Implements an encapsulation in BINARY for encrypted Ripple documents.
4
+ #
5
+ # Example usage:
6
+ # Ripple::Encryption::BinaryDocument.new(config, @document).encrypt
7
+ class BinaryDocument
8
+ # Creates an object that is prepared to encrypt its contents.
9
+ # @param [String] data object to store
10
+ def initialize(config, data)
11
+ config.generate_new_iv
12
+ @config = config
13
+ @data = data
14
+ @encryptor = Ripple::Encryption::Encryptor.new @config.to_h
15
+ end
16
+
17
+ # Converts the data into the encrypted format
18
+ def encrypt
19
+ @config.generate_new_iv
20
+ encrypted_data = @encryptor.encrypt @data
21
+ {:version => Ripple::Encryption::VERSION, :iv => Base64.encode64(@config.to_h['iv']), :data => encrypted_data}
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,61 @@
1
+ module Ripple
2
+ module Encryption
3
+ # Implements the {Riak::Serializer} API for the purpose of
4
+ # encrypting/decrypting Ripple documents as raw binary.
5
+ #
6
+ # Example usage:
7
+ # path = File.join(ROOT_DIR,'config','encryption.yml')
8
+ #
9
+ # ::Riak::Serializers['application/x-binary-encrypted'] = Ripple::Encryption::BinarySerializer.new
10
+ # (
11
+ # OpenSSL::Cipher.new(config['cipher']), path
12
+ # )
13
+ #
14
+ # class MyDocument
15
+ # include Ripple::Document
16
+ # include Ripple::Encryption
17
+ # end
18
+ #
19
+ # @see Encryption
20
+ class BinarySerializer
21
+ REGISTER_KEY = 'application/x-binary-encrypted'
22
+
23
+ # @return [OpenSSL::Cipher, OpenSSL::PKey::*] the cipher used to encrypt the object
24
+ attr_accessor :cipher
25
+
26
+ # Cipher-specific settings
27
+ # @see OpenSSL::Cipher
28
+ attr_accessor :key, :iv, :key_length, :padding
29
+
30
+ # Creates a serializer using the provided cipher and internal
31
+ # content type. Be sure to set the {#key}, {#iv}, {#key_length},
32
+ # {#padding} as appropriate for the cipher before attempting
33
+ # (de-)serialization.
34
+ # @param [OpenSSL::Cipher] cipher the desired
35
+ # encryption/decryption algorithm
36
+ # @param [String] path the File location of 'encryption.yml'
37
+ # private key file
38
+ def initialize(cipher, path)
39
+ @cipher, @content_type = cipher, REGISTER_KEY
40
+ @config = Ripple::Encryption::Config.new(path)
41
+ end
42
+
43
+ # Serializes and encrypts the Ruby object using the assigned
44
+ # cipher and Content-Type.
45
+ # @param [Object] object the Ruby object to serialize/encrypt
46
+ # @return [String] the serialized, encrypted form of the object
47
+ def dump(object)
48
+ BinaryDocument.new(@config, object).encrypt
49
+ end
50
+
51
+ # Decrypts and deserializes the blob using the assigned cipher
52
+ # and Content-Type.
53
+ # @param [String] blob the original content from Riak
54
+ # @return [Object] the decrypted and deserialized object
55
+ def load(object)
56
+ # this serializer now only supports the v2 (0.0.2 - 0.0.4) format
57
+ return EncryptedBinaryDocument.new(@config, object).decrypt
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,26 @@
1
+ module Ripple
2
+ module Encryption
3
+ # Interprets a encapsulation in BINARY for encrypted Ripple documents.
4
+ #
5
+ # Example usage:
6
+ # Ripple::Encryption::EncryptedBinaryDocument.new(@document).encrypt
7
+ class EncryptedBinaryDocument
8
+ # Creates an object that is prepared to decrypt its contents.
9
+ # @param [Hash] data that was stored in Riak, has keys (:version, :iv, :data)
10
+ def initialize(config, data)
11
+ @config = config.to_h.clone
12
+ @data = data
13
+ raise(EncryptedJsonDocumentError, "Missing 'iv' for decryption") unless @data[:iv]
14
+ iv = Base64.decode64 @data[:iv]
15
+ @config.merge!('iv' => iv)
16
+
17
+ @decryptor = Ripple::Encryption::Encryptor.new @config
18
+ end
19
+
20
+ # Returns the original data from the stored encrypted format
21
+ def decrypt
22
+ @decryptor.decrypt @data[:data]
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,12 +1,9 @@
1
1
  module Ripple
2
2
  module Encryption
3
- # Generic error class for Encryptor
4
- class EncryptedJsonDocumentError < StandardError; end
5
-
6
3
  # Interprets a encapsulation in JSON for encrypted Ripple documents.
7
4
  #
8
5
  # Example usage:
9
- # Ripple::Encryption::JsonDocument.new(@document).encrypt
6
+ # Ripple::Encryption::EncryptedJsonDocument.new(@document).encrypt
10
7
  class EncryptedJsonDocument
11
8
  # Creates an object that is prepared to decrypt its contents.
12
9
  # @param [String] data json string that was stored in Riak
@@ -3,21 +3,22 @@ module Ripple
3
3
  # Implements an encapsulation in JSON for encrypted Ripple documents.
4
4
  #
5
5
  # Example usage:
6
- # Ripple::Encryption::JsonDocument.new(@document).encrypt
6
+ # Ripple::Encryption::JsonDocument.new(config, @document).encrypt
7
7
  class JsonDocument
8
8
  # Creates an object that is prepared to encrypt its contents.
9
9
  # @param [String] data object to store
10
10
  def initialize(config, data)
11
- config.activate
12
- @config = config.to_h
11
+ config.generate_new_iv
12
+ @config = config
13
13
  @data = JSON.dump(data)
14
- @encryptor = Ripple::Encryption::Encryptor.new @config
14
+ @encryptor = Ripple::Encryption::Encryptor.new @config.to_h
15
15
  end
16
16
 
17
17
  # Converts the data into the encrypted format
18
18
  def encrypt
19
+ @config.generate_new_iv
19
20
  encrypted_data = @encryptor.encrypt @data
20
- JSON.dump({:version => Ripple::Encryption::VERSION, :iv => Base64.encode64(@config['iv']), :data => Base64.encode64(encrypted_data)})
21
+ JSON.dump({:version => Ripple::Encryption::VERSION, :iv => Base64.encode64(@config.to_h['iv']), :data => Base64.encode64(encrypted_data)})
21
22
  end
22
23
  end
23
24
  end
@@ -0,0 +1,65 @@
1
+ module Ripple
2
+ module Encryption
3
+ # Implements the {Riak::Serializer} API for the purpose of
4
+ # encrypting/decrypting Ripple documents as JSON.
5
+ #
6
+ # Example usage:
7
+ # path = File.join(ROOT_DIR,'config','encryption.yml')
8
+ #
9
+ # ::Riak::Serializers['application/x-json-encrypted'] = Ripple::Encryption::JsonSerializer.new
10
+ # (
11
+ # OpenSSL::Cipher.new(config['cipher']), path
12
+ # )
13
+ #
14
+ # class MyDocument
15
+ # include Ripple::Document
16
+ # include Ripple::Encryption
17
+ # end
18
+ #
19
+ # @see Encryption
20
+ class JsonSerializer
21
+ REGISTER_KEY = 'application/x-json-encrypted'
22
+
23
+ # @return [String] The Content-Type of the internal format,
24
+ # generally "application/json"
25
+ attr_accessor :content_type
26
+
27
+ # @return [OpenSSL::Cipher, OpenSSL::PKey::*] the cipher used to encrypt the object
28
+ attr_accessor :cipher
29
+
30
+ # Cipher-specific settings
31
+ # @see OpenSSL::Cipher
32
+ attr_accessor :key, :iv, :key_length, :padding
33
+
34
+ # Creates a serializer using the provided cipher and internal
35
+ # content type. Be sure to set the {#key}, {#iv}, {#key_length},
36
+ # {#padding} as appropriate for the cipher before attempting
37
+ # (de-)serialization.
38
+ # @param [OpenSSL::Cipher] cipher the desired
39
+ # encryption/decryption algorithm
40
+ # @param [String] path the File location of 'encryption.yml'
41
+ # private key file
42
+ def initialize(cipher, path)
43
+ @cipher, @content_type = cipher, REGISTER_KEY
44
+ @config = Ripple::Encryption::Config.new(path)
45
+ end
46
+
47
+ # Serializes and encrypts the Ruby object using the assigned
48
+ # cipher and Content-Type.
49
+ # @param [Object] object the Ruby object to serialize/encrypt
50
+ # @return [String] the serialized, encrypted form of the object
51
+ def dump(object)
52
+ JsonDocument.new(@config, object).encrypt
53
+ end
54
+
55
+ # Decrypts and deserializes the blob using the assigned cipher
56
+ # and Content-Type.
57
+ # @param [String] blob the original content from Riak
58
+ # @return [Object] the decrypted and deserialized object
59
+ def load(object)
60
+ # this serializer now only supports the v2 (0.0.2 - 0.0.4) format
61
+ return EncryptedJsonDocument.new(@config, object).decrypt
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,5 +1,5 @@
1
1
  module Ripple
2
2
  module Encryption
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
5
5
  end
@@ -17,8 +17,11 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency 'riak-client'
19
19
  gem.add_dependency 'ripple'
20
+ gem.add_dependency 'rake'
20
21
 
21
22
  # Test Dependencies
22
- gem.add_development_dependency 'rake'
23
+ gem.add_development_dependency 'simplecov'
23
24
  gem.add_development_dependency 'mini_shoulda'
25
+ gem.add_development_dependency 'ruby-prof'
26
+ gem.add_development_dependency 'debugger'
24
27
  end
@@ -1,6 +1,15 @@
1
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..'))
2
2
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
3
 
4
+ require 'rake'
5
+
6
+ require 'simplecov'
7
+ SimpleCov.start do
8
+ project_name "Basho - Ripple Encryption"
9
+
10
+ add_filter "/test/"
11
+ end
12
+
4
13
  require 'minitest/autorun'
5
14
  require 'mini_shoulda'
6
15
 
@@ -0,0 +1,53 @@
1
+ require 'helper'
2
+
3
+ class TestJsonDocument < MiniTest::Spec
4
+ context "Ripple::Encryption::BinaryDocument" do
5
+ setup do
6
+ # # get some encryption going
7
+ @config = Ripple::Encryption::Config.new ENV['ENCRYPTION']
8
+ encryptor = Ripple::Encryption::Encryptor.new @config.to_h
9
+
10
+ # this is the data package that we want
11
+ @document = "some data goes here"
12
+
13
+ # this is how we want that data package to actually be stored
14
+ encrypted_value = encryptor.encrypt @document
15
+ @encrypted_document = {:version => Ripple::Encryption::VERSION, :iv => Base64.encode64(@config.to_h['iv']), :data => encrypted_value}
16
+ end
17
+
18
+ should "convert a document to our desired BINARY format" do
19
+ decrypted_document = Ripple::Encryption::EncryptedBinaryDocument.new(@config, @encrypted_document).decrypt
20
+ assert_equal @document, decrypted_document, 'Decrypted BINARY document does not match original'
21
+ end
22
+ end
23
+
24
+ context "Ripple::Encryption::BinaryDocument with no initialization vector" do
25
+ setup do
26
+ # this is the data package that we want
27
+ @document = "some data goes here"
28
+
29
+ # rig a BinaryDocument without an iv
30
+ @config = Ripple::Encryption::Config.new File.expand_path(File.join('..','fixtures','encryption_no_iv.yml'),__FILE__)
31
+ @binary_document = Ripple::Encryption::BinaryDocument.new(@config, @document)
32
+ end
33
+
34
+ should "convert a document to our desired BINARY format and back again" do
35
+ encrypted_document = @binary_document.encrypt
36
+ assert_equal @document, Ripple::Encryption::EncryptedBinaryDocument.new(@config, encrypted_document).decrypt, 'Did not get the BINARY format expected.'
37
+ end
38
+ end
39
+
40
+ context "Ripple::Encryption::BinarySerializer" do
41
+ setup do
42
+ # this is not the default serializer; so we must test independently
43
+ @document = "a binary file of sorts"
44
+ @serializer = Riak::Serializers[Ripple::Encryption::BinarySerializer::REGISTER_KEY]
45
+ end
46
+
47
+ should 'dump & load' do
48
+ encrypted_document = @serializer.dump @document
49
+ result = @serializer.load encrypted_document
50
+ assert_equal @document, result
51
+ end
52
+ end
53
+ end
@@ -1,6 +1,21 @@
1
1
  require 'helper'
2
2
 
3
3
  class TestEncryptor < MiniTest::Spec
4
+ context "Ripple::Encryption Activate" do
5
+ should "raise error if acivate using bad config path" do
6
+ begin
7
+ assert_raises Ripple::Encryption::ConfigError do
8
+ Riak::Serializers['application/x-json-encrypted'] = nil
9
+ Ripple::Encryption.activate 'bad_path'
10
+ end
11
+ ensure
12
+ assert_equal false, Ripple::Encryption.activated?
13
+ Ripple::Encryption.activate ENV['ENCRYPTION']
14
+ assert_equal true, Ripple::Encryption.activated?
15
+ end
16
+ end
17
+ end
18
+
4
19
  context "Ripple::Encryption::Encryptor" do
5
20
  setup do
6
21
  config = Ripple::Encryption::Config.new ENV['ENCRYPTION']
@@ -16,11 +16,17 @@ class TestJsonDocument < MiniTest::Spec
16
16
  end
17
17
 
18
18
  should "convert a document to our desired JSON format" do
19
- assert_equal @encrypted_document, Ripple::Encryption::JsonDocument.new(@config, @document).encrypt, 'Did not get the JSON format expected.'
20
- end
19
+ another_encrypted_document = Ripple::Encryption::JsonDocument.new(@config, @document).encrypt
20
+
21
+ assert another_encrypted_document != @encrypted_document, "Documents have same cipher text, iv may not be unique"
22
+
23
+ assert (JSON.parse another_encrypted_document).has_key?('version'), 'Did not have a version attribute'
24
+ assert (JSON.parse another_encrypted_document).has_key?('iv'), 'Did not have a iv attribute'
25
+ assert (JSON.parse another_encrypted_document).has_key?('data'), 'Did not have a data attribute'
26
+
27
+ decrypted_document = Ripple::Encryption::EncryptedJsonDocument.new(@config, @encrypted_document).decrypt
21
28
 
22
- should "interpret our JSON format into a document" do
23
- assert_equal @document, Ripple::Encryption::EncryptedJsonDocument.new(@config, @encrypted_document).decrypt, 'Did not get the JSON format expected.'
29
+ assert_equal @document, decrypted_document, 'Decrypted JSON document does not match original'
24
30
  end
25
31
  end
26
32
 
@@ -14,14 +14,12 @@ class TestRipple < MiniTest::Spec
14
14
  assert_equal 'here is some new data', read_doc.message
15
15
  end
16
16
 
17
- should "write the ripple document raw confirmation" do
17
+ should "write the current version of Ripple::Encrpytion" do
18
18
  document = TestDocument.new
19
19
  document.message = 'here is some new data'
20
20
  document.save
21
- expected_data = 'VpQTfX23xKdMK4Kprp/xgwDh4UFFSYC8q4OeOhK2zPn0l5huFO+vsoBrq8pT\nd5Z3EdgPx3k8VpL0QNH1FM6m4g==\n'
22
- expected_doc_data = "{\"version\":\"#{Ripple::Encryption::VERSION}\",\"iv\":\"ABYLnUHWE/fIwE2gKYC6hg==\\n\",\"data\":\"#{expected_data}\"}"
23
21
  raw_data = `curl -s http://#{Ripple.config[:host]}:#{Ripple.config[:http_port]}/buckets/#{TestDocument.bucket_name}/keys/#{document.key}`
24
- assert_equal expected_doc_data, raw_data
22
+ assert_equal Ripple::Encryption::VERSION, (JSON.parse raw_data)['version']
25
23
  end
26
24
  end
27
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ripple-encryption
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-03-03 00:00:00.000000000 Z
13
+ date: 2013-07-01 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: riak-client
@@ -46,6 +46,22 @@ dependencies:
46
46
  version: '0'
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: simplecov
49
65
  requirement: !ruby/object:Gem::Requirement
50
66
  none: false
51
67
  requirements:
@@ -76,6 +92,38 @@ dependencies:
76
92
  - - ! '>='
77
93
  - !ruby/object:Gem::Version
78
94
  version: '0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: ruby-prof
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: debugger
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
79
127
  description: Easily encrypt data at rest with minimal changes to existing ripple models.
80
128
  email:
81
129
  - rsecrist@basho.com
@@ -84,6 +132,7 @@ executables: []
84
132
  extensions: []
85
133
  extra_rdoc_files: []
86
134
  files:
135
+ - .gitignore
87
136
  - Gemfile
88
137
  - Gemfile.lock
89
138
  - LICENSE
@@ -95,10 +144,14 @@ files:
95
144
  - lib/ripple-encryption.rb
96
145
  - lib/ripple-encryption/activation.rb
97
146
  - lib/ripple-encryption/config.rb
98
- - lib/ripple-encryption/encrypted_json_document.rb
99
147
  - lib/ripple-encryption/encryptor.rb
100
- - lib/ripple-encryption/json_document.rb
101
- - lib/ripple-encryption/serializer.rb
148
+ - lib/ripple-encryption/errors.rb
149
+ - lib/ripple-encryption/types/binary_document.rb
150
+ - lib/ripple-encryption/types/binary_serializer.rb
151
+ - lib/ripple-encryption/types/encrypted_binary_document.rb
152
+ - lib/ripple-encryption/types/encrypted_json_document.rb
153
+ - lib/ripple-encryption/types/json_document.rb
154
+ - lib/ripple-encryption/types/json_serializer.rb
102
155
  - lib/ripple-encryption/version.rb
103
156
  - ripple-encryption.gemspec
104
157
  - test/fixtures/encryption.yml
@@ -110,6 +163,7 @@ files:
110
163
  - test/fixtures/test_document/v1_doc.riak
111
164
  - test/fixtures/test_document/v2_doc.riak
112
165
  - test/helper.rb
166
+ - test/test_binary_document.rb
113
167
  - test/test_config.rb
114
168
  - test/test_encryptor.rb
115
169
  - test/test_json_document.rb
@@ -149,6 +203,7 @@ test_files:
149
203
  - test/fixtures/test_document/v1_doc.riak
150
204
  - test/fixtures/test_document/v2_doc.riak
151
205
  - test/helper.rb
206
+ - test/test_binary_document.rb
152
207
  - test/test_config.rb
153
208
  - test/test_encryptor.rb
154
209
  - test/test_json_document.rb
@@ -1,117 +0,0 @@
1
- module Ripple
2
- module Encryption
3
- # Implements the {Riak::Serializer} API for the purpose of
4
- # encrypting/decrypting Ripple documents.
5
- #
6
- # Example usage:
7
- # ::Riak::Serializers['application/x-json-encrypted'] = EncryptedSerializer.new(OpenSSL::Cipher.new("AES-256"))
8
- # class MyDocument
9
- # include Ripple::Document
10
- # include Riak::Encryption
11
- # end
12
- #
13
- # @see Encryption
14
- class Serializer
15
- # @return [String] The Content-Type of the internal format,
16
- # generally "application/json"
17
- attr_accessor :content_type
18
-
19
- # @return [OpenSSL::Cipher, OpenSSL::PKey::*] the cipher used to encrypt the object
20
- attr_accessor :cipher
21
-
22
- # Cipher-specific settings
23
- # @see OpenSSL::Cipher
24
- attr_accessor :key, :iv, :key_length, :padding
25
-
26
- # Serialization Options
27
- # @return [true, false] Is the encrypted text also base64 encoded?
28
- attr_accessor :base64
29
-
30
- # Creates a serializer using the provided cipher and internal
31
- # content type. Be sure to set the {#key}, {#iv}, {#key_length},
32
- # {#padding} as appropriate for the cipher before attempting
33
- # (de-)serialization.
34
- # @param [OpenSSL::Cipher] cipher the desired
35
- # encryption/decryption algorithm
36
- # @param [String] content_type the Content-Type of the
37
- # unencrypted contents
38
- def initialize(cipher, content_type='application/json', path)
39
- @cipher, @content_type = cipher, content_type
40
- @config = Ripple::Encryption::Config.new(path)
41
- end
42
-
43
- # Serializes and encrypts the Ruby object using the assigned
44
- # cipher and Content-Type.
45
- # @param [Object] object the Ruby object to serialize/encrypt
46
- # @return [String] the serialized, encrypted form of the object
47
- def dump(object)
48
- JsonDocument.new(@config, object).encrypt
49
- end
50
-
51
- # Decrypts and deserializes the blob using the assigned cipher
52
- # and Content-Type.
53
- # @param [String] blob the original content from Riak
54
- # @return [Object] the decrypted and deserialized object
55
- def load(object)
56
- # try the v1 way first
57
- begin
58
- internal = decrypt(object)
59
- return ::Riak::Serializers.deserialize('application/json', internal)
60
- # if that doesn't work, try the v2 way
61
- rescue OpenSSL::Cipher::CipherError, MultiJson::DecodeError
62
- return EncryptedJsonDocument.new(@config, object).decrypt
63
- end
64
- end
65
-
66
- private
67
-
68
- # generates a new iv each call unless a static (less secure)
69
- # iv is used.
70
- def encrypt(object)
71
- old_version = '0.0.1'
72
- result = ''
73
- if cipher.respond_to?(:iv=) and @iv == nil
74
- iv = OpenSSL::Random.random_bytes(cipher.iv_len)
75
- cipher.iv = iv
76
- result << old_version << iv
77
- end
78
-
79
- if cipher.respond_to?(:public_encrypt)
80
- result << cipher.public_encrypt(object)
81
- else
82
- cipher_setup :encrypt
83
- result << cipher.update(object) << cipher.final
84
- cipher.reset
85
- end
86
- return result
87
- end
88
-
89
- def decrypt(cipher_text)
90
- old_version = '0.0.1'
91
-
92
- if cipher.respond_to?(:iv=) and @iv == nil
93
- version = cipher_text.slice(0, old_version.length)
94
- cipher.iv = cipher_text.slice(old_version.length, cipher.iv_len)
95
- cipher_text = cipher_text.slice(old_version.length + cipher.iv_len, cipher_text.length)
96
- end
97
-
98
- if cipher.respond_to?(:private_decrypt)
99
- cipher.private_decrypt(cipher_text)
100
- else
101
- cipher_setup :decrypt
102
- result = cipher.update(cipher_text) << cipher.final
103
- cipher.reset
104
- result
105
- end
106
- end
107
-
108
- def cipher_setup(mode)
109
- cipher.send mode
110
- cipher.key = key if key
111
- cipher.iv = iv if iv
112
- cipher.key_length = key_length if key_length
113
- cipher.padding = padding if padding
114
- end
115
- end
116
- end
117
- end