ork-encryption 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0d98c6c7652d8bf6ceb94c40a8f32d2dce5135fc
4
+ data.tar.gz: 08b286150cdc8a6582d92fa6357811d643e30b57
5
+ SHA512:
6
+ metadata.gz: f10fc38e89d28c5a551013e99b3e5ffe04fb63a02a37865ae7e9add307030d871fc82eb15122171da33e9344e83b8153ab4d424da431976969e1c0151b3d7dff
7
+ data.tar.gz: c1ef9588c03f0abc78498ad8b5d20bb9e428f219ae8510bd9e0212483530b443af2389e832d93e2e3b9fe4429f216185768d98b3f0942ccd2bfff87944999d2c
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ ork-encryption
2
+ ==============
3
+
4
+ The ork-encryption gem provides encryption and decryption for Ork models.
data/lib/ork/cipher.rb ADDED
@@ -0,0 +1,72 @@
1
+ require 'openssl'
2
+
3
+ module Ork::Encryption
4
+
5
+ # Implements a simple object that can either
6
+ # encrypt or decrypt arbitrary data.
7
+ #
8
+ # Example:
9
+ # cipher = Ork::Encryption::Cipher.new config_hash
10
+ # cipher.encrypt stuff
11
+ # cipher.decrypt stuff
12
+ #
13
+ class Cipher
14
+
15
+ # Creates a cipher that is prepared to encrypt/decrypt a blob.
16
+ # @param [Hash] config the key/cipher/iv needed to initialize OpenSSL
17
+ #
18
+ def initialize(config = {})
19
+ Cipher.validate_config @config = config
20
+ @cipher = OpenSSL::Cipher.new @config[:cipher]
21
+ end
22
+
23
+ # Validates the configuration has all the required values to
24
+ # encrypt and decrypt an object
25
+ #
26
+ # Note: if the configuration is invalid, an
27
+ # `Ork::Encryption::MissingConfig` error is raised.
28
+ #
29
+ def self.validate_config(config)
30
+ if config.nil? || ([:cipher, :key] - config.keys).any?
31
+ raise MissingConfig,
32
+ 'Make sure to provide the full configuration to Ork::Encryption. ' +
33
+ 'Use Ork::Encryption.init(config_hash) to set the configuration ' +
34
+ 'or assert that Ork::Encryption::Cipher.new receives a non empty' +
35
+ ' hash with :cipher and :key values.'
36
+ end
37
+ end
38
+
39
+ def random_iv!
40
+ self.iv = @cipher.random_iv
41
+ end
42
+
43
+ def iv=(iv)
44
+ @config[:iv] = iv
45
+ end
46
+
47
+ # Encrypt stuff.
48
+ # @param [Object] blob the data to encrypt
49
+ def encrypt(blob)
50
+ initialize_cipher_for :encrypt
51
+ "#{@cipher.update blob}#{@cipher.final}"
52
+ end
53
+
54
+ # Decrypt stuff.
55
+ # @param [Object] blob the encrypted data to decrypt
56
+ def decrypt(blob)
57
+ initialize_cipher_for :decrypt
58
+ "#{@cipher.update blob}#{@cipher.final}"
59
+ end
60
+
61
+ private
62
+
63
+ # This sets the mode so OpenSSL knows to encrypt or decrypt, etc.
64
+ # @param [Symbol] mode either :encrypt or :decrypt
65
+ def initialize_cipher_for(mode)
66
+ @cipher.send mode
67
+ @cipher.key = @config[:key]
68
+ @cipher.iv = @config[:iv]
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'cipher'
2
+ require_relative 'errors'
3
+ require_relative 'serializers/json'
4
+
5
+ module Ork
6
+ module Encryption
7
+ VERSION = '0.0.1'
8
+
9
+ def self.included(klass)
10
+ raise NotAnOrkDocument unless klass.included_modules.include? Ork::Document
11
+ klass.content_type Serializers::Json.content_type
12
+ end
13
+
14
+
15
+ # Initializes the module, setting a configuration and registering
16
+ # the serializers into Riak API.
17
+ #
18
+ def self.init(config)
19
+ Serializers::Json.register!
20
+
21
+ encryption_config config
22
+ end
23
+
24
+ # Accessor for the general Encryptor config.
25
+ #
26
+ # config - When nil, it acts like a reader.
27
+ # When hash, it needs :key and :cipher
28
+ #
29
+ # Raises Ork::Encryption::MissingConfig when the config is incomplete.
30
+ #
31
+ def self.encryption_config(config = nil)
32
+ return @encryption_config if config.nil?
33
+
34
+ Ork::Encryption::Cipher.validate_config @encryption_config = config
35
+ end
36
+
37
+ end
38
+ end
data/lib/ork/errors.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Ork
2
+ module Encryption
3
+
4
+ class NotAnOrkDocument < StandardError; end
5
+ class MissingConfig < StandardError; end
6
+ end
7
+ end
8
+
@@ -0,0 +1,59 @@
1
+ module Ork::Encryption
2
+ module Serializers
3
+
4
+ # Implements the {Riak::Serializer} API for the purpose of
5
+ # encrypting/decrypting Ork documents as JSON.
6
+ #
7
+ # @see Encryption
8
+ class Json
9
+
10
+ # The Content-Type of the internal format
11
+ def self.content_type
12
+ 'application/x-json-encrypted'
13
+ end
14
+
15
+ # Register the serializer into Riak
16
+ def self.register!
17
+ Riak::Serializers[content_type] = self
18
+ end
19
+
20
+ # Serializes and encrypts the Ruby hash using the assigned
21
+ # cipher and Content-Type.
22
+ #
23
+ # data - Hash representing persisted_data to serialize/encrypt.
24
+ #
25
+ def self.dump(data)
26
+ json_attributes = data.to_json(Riak.json_options)
27
+
28
+ encrypted_object = {
29
+ iv: Base64.encode64(cipher.random_iv!),
30
+ data: Base64.encode64(cipher.encrypt json_attributes),
31
+ version: Ork::Encryption::VERSION
32
+ }
33
+
34
+ encrypted_object.to_json(Riak.json_options)
35
+ end
36
+
37
+ # Decrypts and deserializes the blob using the assigned cipher
38
+ # and Content-Type.
39
+ #
40
+ # blob - String of the original content from Riak
41
+ #
42
+ def self.load(blob)
43
+ encrypted_object = Riak::JSON.parse(blob)
44
+ cipher.iv = Base64.decode64 encrypted_object['iv']
45
+ decoded_data = Base64.decode64 encrypted_object['data']
46
+
47
+ # this serializer now only supports the v2 (0.0.2 - 0.0.4) format
48
+ Riak::JSON.parse(cipher.decrypt decoded_data)
49
+ end
50
+
51
+ private
52
+
53
+ def self.cipher
54
+ @cipher ||= Cipher.new(Ork::Encryption.encryption_config)
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'ork-encryption'
3
+ s.version = '0.0.1'
4
+ s.date = Time.now.strftime('%Y-%m-%d')
5
+ s.summary = 'Ruby modeling layer for Riak.'
6
+ s.summary = 'A simple encryption library for Ork::Documents stored in riak.'
7
+ s.description = 'Ork is a small Ruby modeling layer for Riak, inspired by Ohm.'
8
+ s.description = 'Encrypt documents persisted on Riak DB. Inspired in ripple-encryption'
9
+ s.authors = ['Emiliano Mancuso']
10
+ s.email = ['emiliano.mancuso@gmail.com']
11
+ s.homepage = 'http://github.com/emancu/ork-encryption'
12
+ s.license = 'MIT'
13
+
14
+ s.files = Dir[
15
+ 'README.md',
16
+ 'rakefile',
17
+ 'lib/**/*.rb',
18
+ '*.gemspec'
19
+ ]
20
+ s.test_files = Dir['test/*.*']
21
+
22
+ s.add_dependency 'riak-client'
23
+ s.add_dependency 'ork', "~> 0.1.1"
24
+ s.add_development_dependency 'protest'
25
+ s.add_development_dependency 'mocha'
26
+ s.add_development_dependency 'coveralls'
27
+ end
28
+
data/rakefile ADDED
@@ -0,0 +1,10 @@
1
+ task :default => :test
2
+
3
+ ENV['ORK_RIAK_URL'] ||= 'http://localhost:8098'
4
+
5
+ desc 'Run tests'
6
+ task :test do
7
+ require File.expand_path("./test/helper", File.dirname(__FILE__))
8
+
9
+ Dir["test/**/*_test.rb"].each { |file| load file }
10
+ end
@@ -0,0 +1,39 @@
1
+ require_relative 'helper'
2
+
3
+ Protest.describe 'Ork::Encryption::Cipher' do
4
+ setup do
5
+ config = {
6
+ cipher: 'AES-256-CBC',
7
+ key: 'fantasticobscurekeygoesherenowty',
8
+ iv: 'an_iv_really_easy'
9
+ }
10
+
11
+ @cipher = Ork::Encryption::Cipher.new config
12
+ @text = "This is some nifty text."
13
+ # this is the example text encrypted (binary string literals use UTF-8 in ruby 2.0
14
+ @blob = "\xCA\x0F\x80\x9D&)lU\x97h\xC9\xAD\x16+\xBC\xAAQ\xD9\xC7C\x8F\xD7\xEFDoRoS\x0E\xEC\xD3\xA6"
15
+ @blob = @blob.force_encoding('ASCII-8BIT')
16
+ end
17
+
18
+ test "convert text to an encrypted blob" do
19
+ assert_equal @blob, @cipher.encrypt(@text), "Encryption failed."
20
+ end
21
+
22
+ test "convert encrypted blob to text" do
23
+ assert_equal @text, @cipher.decrypt(@blob), "Decryption failed."
24
+ end
25
+
26
+ context "With missing parameter" do
27
+ test "raise an error if key is missing" do
28
+ assert_raise Ork::Encryption::MissingConfig do
29
+ Ork::Encryption::Cipher.new(iv: 'iv', cipher: 'AES-256-CBC')
30
+ end
31
+ end
32
+
33
+ test "raise an error if cipher is missing" do
34
+ assert_raise Ork::Encryption::MissingConfig do
35
+ Ork::Encryption::Cipher.new(key: 'key')
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,115 @@
1
+ require_relative 'helper'
2
+ require 'mocha/api'
3
+ # require 'json'
4
+
5
+ include(Mocha::API)
6
+
7
+
8
+ class Event
9
+ include Ork::Document
10
+ include Ork::Encryption
11
+
12
+ attribute :name
13
+ end
14
+
15
+ config_hash = {
16
+ cipher: 'AES-256-CBC',
17
+ key: 'fantasticobscurekeygoesherenowty'
18
+ }
19
+
20
+ Protest.describe 'Ork::Encryption' do
21
+ context 'include Ork::Encryption' do
22
+ test 'raise an error if it is not a Ork::Document' do
23
+ assert_raise Ork::Encryption::NotAnOrkDocument do
24
+ class NotADocument
25
+ include Ork::Encryption
26
+ end
27
+ end
28
+ end
29
+
30
+ test 'set @content_type' do
31
+ assert_equal 'application/x-json-encrypted', Event.content_type
32
+ end
33
+ end
34
+
35
+ context 'init' do
36
+ test 'register the serializers on Riak API' do
37
+ assert_equal Ork::Encryption::Serializers::Json,
38
+ Riak::Serializers['application/x-json-encrypted']
39
+ end
40
+
41
+ test 'raise an error if config is invalid' do
42
+ assert_raise Ork::Encryption::MissingConfig do
43
+ Ork::Encryption.init(cipher: 'AES-256-CBC')
44
+ end
45
+ end
46
+
47
+ test 'encryption_config is set with the same config of Ork::Encryption' do
48
+ Ork::Encryption.init config_hash
49
+
50
+ assert_equal config_hash, Ork::Encryption.encryption_config
51
+ end
52
+ end
53
+
54
+ context 'encrypt / decrypt' do
55
+ Ork::Encryption.init config_hash
56
+
57
+ class Event
58
+ include Ork::Encryption # reload module
59
+ end
60
+
61
+ setup do
62
+ @iv = 'an_iv_really_easy'
63
+ OpenSSL::Cipher.any_instance.stubs(:random_iv).returns(@iv)
64
+
65
+ cipher = Ork::Encryption::Cipher.new(config_hash)
66
+ cipher.random_iv!
67
+
68
+ @event = Event.create name: 'Encryption'
69
+ @attributes = {'name' => 'Encryption', '_type' => 'Event'}
70
+ @json_attributes = JSON.dump @attributes
71
+ @encrypted_attributes = cipher.encrypt @json_attributes
72
+
73
+ @raw_data = raw_data_from_riak @event
74
+ @raw_data = JSON.parse @raw_data
75
+ end
76
+
77
+ teardown do
78
+ OpenSSL::Cipher.any_instance.unstub(:random_iv)
79
+ end
80
+
81
+ test 'saving the object stores attributes encoded in Base64' do
82
+ assert_equal Base64.encode64(@encrypted_attributes), @raw_data['data']
83
+ end
84
+
85
+ test 'saving the object stores the encrypted attributes' do
86
+ assert_equal @encrypted_attributes, Base64.decode64(@raw_data['data'])
87
+ end
88
+
89
+ test 'the IV is stored with the encrypted data' do
90
+ assert_equal Base64.encode64(@iv), @raw_data['iv']
91
+ end
92
+
93
+ test 'the IV is stored with the encrypted data' do
94
+ assert_equal @iv, Base64.decode64(@raw_data['iv'])
95
+ end
96
+
97
+ test 'the VERSION of Ork::Encryption is stored with the encrypted data' do
98
+ assert_equal Ork::Encryption::VERSION, @raw_data['version']
99
+ end
100
+
101
+ test 'loading an object decrypts the attributes' do
102
+ assert_equal({name: 'Encryption'}, Event[@event.id].attributes)
103
+ end
104
+
105
+ private
106
+
107
+ def raw_data_from_riak(object)
108
+ url = "#{ENV['ORK_RIAK_URL']}" +
109
+ "/buckets/#{object.class.bucket_name}/keys/#{object.id}"
110
+
111
+ `curl -s -XGET #{url}`
112
+ end
113
+
114
+ end
115
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
2
+
3
+ require 'coveralls'
4
+ Coveralls.wear!
5
+
6
+ SimpleCov.start do
7
+ project_name "Ork-Encryptor"
8
+ command_name "Protest"
9
+
10
+ add_filter "/test/"
11
+ end
12
+
13
+ require "rubygems"
14
+ require "protest"
15
+ require "ork"
16
+ require 'ork/encryption'
17
+
18
+ Riak.disable_list_keys_warnings = true
19
+ Protest.report_with(:progress)
20
+
21
+ def deny(condition, message="Expected condition to be unsatisfied")
22
+ assert !condition, message
23
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ork-encryption
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Emiliano Mancuso
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: riak-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ork
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: protest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mocha
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coveralls
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Encrypt documents persisted on Riak DB. Inspired in ripple-encryption
84
+ email:
85
+ - emiliano.mancuso@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - README.md
91
+ - rakefile
92
+ - lib/ork/cipher.rb
93
+ - lib/ork/encryption.rb
94
+ - lib/ork/errors.rb
95
+ - lib/ork/serializers/json.rb
96
+ - ork-encryption.gemspec
97
+ - test/cipher_test.rb
98
+ - test/encrypt_test.rb
99
+ - test/helper.rb
100
+ homepage: http://github.com/emancu/ork-encryption
101
+ licenses:
102
+ - MIT
103
+ metadata: {}
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 2.1.9
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: A simple encryption library for Ork::Documents stored in riak.
124
+ test_files:
125
+ - test/cipher_test.rb
126
+ - test/encrypt_test.rb
127
+ - test/helper.rb