asherah 0.1.0.beta.2-x86_64-darwin → 0.3.0-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3e07fa915ec849dcddfa6a309ddb834baf0060bc420a3ea42e521b127b055ba
4
- data.tar.gz: 6c91eb6493ad293f7a66d301d67abb392db99de28cd6254b3fc3ce136b3e6c77
3
+ metadata.gz: 19b2444c560043be159c67a8ce073d195efdc97621bf2bc83aa51ccf782e05cf
4
+ data.tar.gz: d8cc8af342fe2738ff2775f87ac2a5a708a3efc22fd1abc5c1ce31c75bb31abf
5
5
  SHA512:
6
- metadata.gz: cef747ccb3d115a4a755e751961c8a2fb3b922f6d6166391332dc07bfa4c47db24aeaca0708100b61f6c6f2048d694786bf4b2bca347df1c9b8c62bc5e0ea517
7
- data.tar.gz: 28d44374434998f0b2b4c4fdfc9a1006a60a6017c939fc6d58dd83b4fcbaa6e913eeba0d75fd4b85d7751fd6b36d40e936f1df3a91a825eceaa14d1ce94623b7
6
+ metadata.gz: e3306522c79aba79a641be8be76e8dd884717a229cad7ab1f880a3ff1918691e24c6e4021fdc73431446d9dbb8c60d389d260f2358bc07f728f88980609bdbdc
7
+ data.tar.gz: d3afd3c3a65aa26183328496a75a2e278764b4056516ea8a1fcd5121109aaf07078f8089ff43ed2e125532052dac3da9efa5c50ea826dd12273ed030acec36b6
data/.rubocop.yml CHANGED
@@ -4,6 +4,7 @@ AllCops:
4
4
  SuggestExtensions: false
5
5
  Exclude:
6
6
  - 'vendor/**/*' # Github Actions
7
+ - 'tmp/**/*'
7
8
 
8
9
  Layout/LineLength:
9
10
  Max: 120
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2022-03-22
4
+
5
+ - Free up cobhan buffers after encrypt/decrypt to prevent growing heap memory
6
+ - Use local `estimate_buffer` calculation instead of FFI call
7
+ - Upgrade to use asherah-cobhan v0.4.3
8
+
9
+ ## [0.2.0] - 2022-03-21
10
+
11
+ - Implement versioning for asherah-cobhan binaries
12
+ - Upgrade to use asherah-cobhan v0.3.1
13
+ - Add BadConfig error and expose error codes
14
+ - Remove DRR methods and use JSON exclusively
15
+ - Cross language testing using Asherah Go
16
+
17
+ ## [0.1.0] - 2022-03-14
18
+
19
+ - First official release
3
20
 
4
21
  ## [0.1.0.beta2] - 2022-03-14
5
22
 
data/Gemfile CHANGED
@@ -6,3 +6,5 @@ source 'https://rubygems.org'
6
6
  gemspec
7
7
 
8
8
  gem 'rake', '~> 13.0'
9
+
10
+ gem 'cucumber', '~> 7.1.0'
data/README.md CHANGED
@@ -34,10 +34,10 @@ Configure Asherah:
34
34
 
35
35
  ```ruby
36
36
  Asherah.configure do |config|
37
- config.kms_type = 'static'
37
+ config.kms = 'static'
38
38
  config.metastore = 'memory'
39
- config.service_name = 'gem'
40
- config.product_id = 'sable'
39
+ config.service_name = 'service'
40
+ config.product_id = 'product'
41
41
  end
42
42
  ```
43
43
 
@@ -46,15 +46,15 @@ Encrypt some data for a `partition_id`
46
46
  ```ruby
47
47
  partition_id = 'user_1'
48
48
  data = 'Some PII data'
49
- data_row_record = Asherah.encrypt(partition_id, data)
50
- p data_row_record
49
+ data_row_record_json = Asherah.encrypt(partition_id, data)
50
+ puts data_row_record_json
51
51
  ```
52
52
 
53
- Decrypt `data_row_record`
53
+ Decrypt `data_row_record_json`
54
54
 
55
55
  ```ruby
56
- decrypted_data = Asherah.decrypt(partition_id, data_row_record)
57
- p decrypted_data
56
+ decrypted_data = Asherah.decrypt(partition_id, data_row_record_json)
57
+ puts decrypted_data
58
58
  ```
59
59
 
60
60
  ## Development
@@ -67,6 +67,17 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
67
67
 
68
68
  Bug reports and pull requests are welcome on GitHub at https://github.com/godaddy/asherah-ruby.
69
69
 
70
+ ## Releasing new gem version
71
+
72
+ ```
73
+ # Create and push a version tag
74
+ git tag -a v$(rake version) -m "Version $(rake version)"
75
+ git push origin v$(rake version)
76
+
77
+ # Create a release in Github to trigger .github/workflows/publish.yml workflow
78
+ echo "Version $(rake version)"
79
+ ```
80
+
70
81
  ## License
71
82
 
72
83
  The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
data/Rakefile CHANGED
@@ -3,7 +3,6 @@
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
5
  require 'rubygems/package'
6
- require 'open-uri'
7
6
 
8
7
  RSpec::Core::RakeTask.new(:spec)
9
8
 
@@ -13,6 +12,7 @@ RuboCop::RakeTask.new
13
12
 
14
13
  task default: %i[spec rubocop]
15
14
 
15
+ ASHERAH_BIN = 'bin/download-asherah.sh'
16
16
  DISTRIBUTIONS = {
17
17
  'x86_64-linux' => ['libasherah-x64.so'],
18
18
  'x86_64-darwin' => ['libasherah-x64.dylib'],
@@ -20,6 +20,19 @@ DISTRIBUTIONS = {
20
20
  'arm64-darwin' => ['libasherah-arm64.dylib']
21
21
  }.freeze
22
22
 
23
+ def current_filename
24
+ @current_filename ||=
25
+ begin
26
+ require 'cobhan'
27
+ Class.new.extend(Cobhan).library_file_name('libasherah')
28
+ end
29
+ end
30
+
31
+ def current_platform
32
+ @distribution ||= DISTRIBUTIONS.detect { |_k, v| v.include?(current_filename) }
33
+ @distribution.first
34
+ end
35
+
23
36
  def native_build(platform, native_files)
24
37
  puts "Building gem for #{platform}"
25
38
 
@@ -32,14 +45,14 @@ def native_build(platform, native_files)
32
45
 
33
46
  # Copy files to tmp gem dir
34
47
  gemspec = Bundler.load_gemspec('asherah.gemspec')
35
- gemspec.files.each do |file|
48
+ (gemspec.files + [ASHERAH_BIN]).each do |file|
36
49
  dir = File.dirname(file)
37
50
  filename = File.basename(file)
38
51
  FileUtils.mkdir_p(File.join(tmp_gem_dir, dir))
39
52
  FileUtils.copy_file(file, File.join(tmp_gem_dir, dir, filename))
40
53
  end
41
54
 
42
- # Set platform for native gem build and remove extentions
55
+ # Set platform for native gem build
43
56
  gemspec.platform = Gem::Platform.new(platform)
44
57
 
45
58
  native_dir = 'lib/asherah/native'
@@ -47,16 +60,16 @@ def native_build(platform, native_files)
47
60
  FileUtils.mkdir_p(native_dir)
48
61
  native_files.each do |native_file|
49
62
  native_file_path = File.join(native_dir, native_file)
50
- gemspec.files << native_file_path
51
63
 
52
- File.open(native_file_path, 'wb') do |file|
53
- url = "https://github.com/godaddy/asherah-cobhan/releases/download/current/#{native_file}"
54
- puts "Downloading #{url}"
55
- file << URI.parse(url).open.read
56
- end
64
+ # Download native file
65
+ download_asherah_path = File.join(tmp_gem_dir, ASHERAH_BIN)
66
+ system("#{download_asherah_path} #{native_file}")
67
+
68
+ # Add native file in gemspec
69
+ gemspec.files << native_file_path
57
70
  end
58
71
 
59
- package = Gem::Package.build gemspec
72
+ package = Gem::Package.build(gemspec)
60
73
  FileUtils.mv package, File.join(pkg_dir, package)
61
74
  end
62
75
  end
@@ -78,19 +91,31 @@ namespace :native do
78
91
  end
79
92
  end
80
93
 
81
- namespace :smoke do
82
- require 'cobhan'
94
+ namespace :current do
95
+ desc 'Download asherah binary for current platform'
96
+ task :download do
97
+ download_asherah_path = File.join(__dir__, ASHERAH_BIN)
98
+ system("#{download_asherah_path} #{current_filename}")
99
+ end
83
100
 
84
- filename = Class.new.extend(Cobhan).library_file_name('libasherah')
85
- platform, _files = DISTRIBUTIONS.detect { |_k, v| v.include?(filename) }
101
+ desc 'Build native gem for current platform'
102
+ task :build do
103
+ native_build(current_platform, DISTRIBUTIONS[current_platform])
104
+ end
86
105
 
87
- desc "Smoke test native gem on #{platform} platform"
88
- task "#{platform}": :"build:#{platform}" do
106
+ desc 'Smoke test native gem for current platform'
107
+ task smoke: :build do
108
+ platform = current_platform
89
109
  gemspec = Bundler.load_gemspec('asherah.gemspec')
90
110
  gemspec.platform = Gem::Platform.new(platform)
91
111
 
112
+ sh('gem uninstall asherah')
92
113
  sh("gem install pkg/#{gemspec.file_name}")
93
114
  sh('ruby spec/smoke_test.rb')
94
115
  end
95
116
  end
96
117
  end
118
+
119
+ task :version do
120
+ puts Asherah::VERSION
121
+ end
data/asherah.gemspec CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
35
35
  spec.require_paths = ['lib']
36
36
 
37
- spec.add_dependency 'cobhan', '~> 0.1.2'
37
+ spec.add_dependency 'cobhan', '~> 0.2.0'
38
38
  spec.add_development_dependency 'dotenv', '~> 2.7.6'
39
39
  spec.add_development_dependency 'rspec', '~> 3.10.0'
40
40
  spec.add_development_dependency 'rubocop', '~> 1.7'
data/lib/asherah/error.rb CHANGED
@@ -9,20 +9,22 @@ module Asherah
9
9
  GetSessionFailed = Class.new(StandardError)
10
10
  EncryptFailed = Class.new(StandardError)
11
11
  DecryptFailed = Class.new(StandardError)
12
+ BadConfig = Class.new(StandardError)
12
13
 
13
14
  CODES = {
14
15
  -100 => NotInitialized,
15
16
  -101 => AlreadyInitialized,
16
17
  -102 => GetSessionFailed,
17
18
  -103 => EncryptFailed,
18
- -104 => DecryptFailed
19
+ -104 => DecryptFailed,
20
+ -105 => BadConfig
19
21
  }.freeze
20
22
 
21
23
  def self.check_result!(result, message)
22
24
  return unless result.negative?
23
25
 
24
26
  error_class = Error::CODES.fetch(result, StandardError)
25
- raise error_class, message
27
+ raise error_class, "#{message} (#{result})"
26
28
  end
27
29
  end
28
30
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Asherah
4
- VERSION = '0.1.0.beta.2'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/asherah.rb CHANGED
@@ -3,9 +3,6 @@
3
3
  require_relative 'asherah/version'
4
4
  require 'asherah/config'
5
5
  require 'asherah/error'
6
- require 'asherah/key_meta'
7
- require 'asherah/data_row_record'
8
- require 'asherah/envelope_key_record'
9
6
  require 'cobhan'
10
7
 
11
8
  # Asherah is a Ruby wrapper around Asherah Go application-layer encryption SDK.
@@ -15,13 +12,15 @@ module Asherah
15
12
  LIB_ROOT_PATH = File.expand_path('asherah/native', __dir__)
16
13
  load_library(LIB_ROOT_PATH, 'libasherah', [
17
14
  [:SetupJson, [:pointer], :int32],
18
- [:Encrypt, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int32],
19
- [:Decrypt, [:pointer, :pointer, :pointer, :int64, :pointer, :int64, :pointer], :int32],
20
15
  [:EncryptToJson, [:pointer, :pointer, :pointer], :int32],
21
16
  [:DecryptFromJson, [:pointer, :pointer, :pointer], :int32],
22
17
  [:Shutdown, [], :void]
23
18
  ].freeze)
24
19
 
20
+ ESTIMATED_ENCRYPTION_OVERHEAD = 48
21
+ ESTIMATED_ENVELOPE_OVERHEAD = 185
22
+ BASE64_OVERHEAD = 1.34
23
+
25
24
  class << self
26
25
  # Configures Asherah
27
26
  #
@@ -31,6 +30,7 @@ module Asherah
31
30
  config = Config.new
32
31
  yield config
33
32
  config.validate!
33
+ @intermediated_key_overhead_bytesize = config.product_id.bytesize + config.service_name.bytesize
34
34
 
35
35
  config_buffer = string_to_cbuffer(config.to_json)
36
36
 
@@ -38,110 +38,65 @@ module Asherah
38
38
  Error.check_result!(result, 'SetupJson failed')
39
39
  end
40
40
 
41
- # Encrypts data for a given partition_id and returns DataRowRecord
41
+ # Encrypts data for a given partition_id and returns DataRowRecord in JSON format.
42
42
  #
43
- # @param partition_id [String]
44
- # @param data [String]
45
- # @return [DataRowRecord]
46
- def encrypt(partition_id, data)
47
- partition_id_buffer = string_to_cbuffer(partition_id)
48
- data_buffer = string_to_cbuffer(data)
49
- output_encrypted_data_buffer = allocate_cbuffer(data.length + 256)
50
- output_encrypted_key_buffer = allocate_cbuffer(256)
51
- output_created_buffer = int_to_buffer(0)
52
- output_parent_key_id_buffer = allocate_cbuffer(256)
53
- output_parent_key_created_buffer = int_to_buffer(0)
54
-
55
- result = Encrypt(
56
- partition_id_buffer,
57
- data_buffer,
58
- output_encrypted_data_buffer,
59
- output_encrypted_key_buffer,
60
- output_created_buffer,
61
- output_parent_key_id_buffer,
62
- output_parent_key_created_buffer
63
- )
64
- Error.check_result!(result, 'Encrypt failed')
65
-
66
- parent_key_meta = KeyMeta.new(
67
- id: cbuffer_to_string(output_parent_key_id_buffer),
68
- created: buffer_to_int(output_parent_key_created_buffer)
69
- )
70
- envelope_key_record = EnvelopeKeyRecord.new(
71
- encrypted_key: cbuffer_to_string(output_encrypted_key_buffer),
72
- created: buffer_to_int(output_created_buffer),
73
- parent_key_meta: parent_key_meta
74
- )
75
-
76
- DataRowRecord.new(
77
- data: cbuffer_to_string(output_encrypted_data_buffer),
78
- key: envelope_key_record
79
- )
80
- end
81
-
82
- # Decrypts a data_row_record for a partition_id and returns decrypted data
43
+ # DataRowRecord contains the encrypted key and data, as well as the information
44
+ # required to decrypt the key encryption key. This object data should be stored
45
+ # in your data persistence as it's required to decrypt data.
83
46
  #
84
- # @param partition_id [String]
85
- # @param data_row_record [DataRowRecord]
86
- # @return [String], Decrypted data
87
- def decrypt(partition_id, data_row_record)
88
- partition_id_buffer = string_to_cbuffer(partition_id)
89
- encrypted_data_buffer = string_to_cbuffer(data_row_record.data)
90
- encrypted_key_buffer = string_to_cbuffer(data_row_record.key.encrypted_key)
91
- created = data_row_record.key.created
92
- parent_key_id_buffer = string_to_cbuffer(data_row_record.key.parent_key_meta.id)
93
- parent_key_created = data_row_record.key.parent_key_meta.created
94
-
95
- output_data_buffer = allocate_cbuffer(encrypted_data_buffer.size + 256)
96
-
97
- result = Decrypt(
98
- partition_id_buffer,
99
- encrypted_data_buffer,
100
- encrypted_key_buffer,
101
- created,
102
- parent_key_id_buffer,
103
- parent_key_created,
104
- output_data_buffer
105
- )
106
- Error.check_result!(result, 'Decrypt failed')
107
-
108
- cbuffer_to_string(output_data_buffer)
109
- end
110
-
111
- def shutdown
112
- Shutdown()
113
- end
114
-
115
- # Encrypts data for a given partition_id and returns DataRowRecord in JSON format
47
+ # EnvelopeKeyRecord represents an encrypted key and is the data structure used
48
+ # to persist the key in the key table. It also contains the meta data
49
+ # of the key used to encrypt it.
50
+ #
51
+ # KeyMeta contains the `id` and `created` timestamp for an encryption key.
116
52
  #
117
53
  # @param partition_id [String]
118
54
  # @param data [String]
119
55
  # @return [String], DataRowRecord in JSON format
120
- def encrypt_to_json(partition_id, data)
56
+ def encrypt(partition_id, data)
121
57
  partition_id_buffer = string_to_cbuffer(partition_id)
122
58
  data_buffer = string_to_cbuffer(data)
123
- output_buffer = allocate_cbuffer(data.length + 256)
59
+ estimated_buffer_bytesize = estimate_buffer(data.bytesize, partition_id.bytesize)
60
+ output_buffer = allocate_cbuffer(estimated_buffer_bytesize)
124
61
 
125
62
  result = EncryptToJson(partition_id_buffer, data_buffer, output_buffer)
126
63
  Error.check_result!(result, 'EncryptToJson failed')
127
64
 
128
65
  cbuffer_to_string(output_buffer)
66
+ ensure
67
+ [partition_id_buffer, data_buffer, output_buffer].map(&:free)
129
68
  end
130
69
 
131
- # Decrypts a DataRowRecord in JSON format for a partition_id and returns decrypted data
70
+ # Decrypts a DataRowRecord in JSON format for a partition_id and returns decrypted data.
132
71
  #
133
72
  # @param partition_id [String]
134
73
  # @param json [String], DataRowRecord in JSON format
135
74
  # @return [String], Decrypted data
136
- def decrypt_from_json(partition_id, json)
75
+ def decrypt(partition_id, json)
137
76
  partition_id_buffer = string_to_cbuffer(partition_id)
138
77
  data_buffer = string_to_cbuffer(json)
139
- output_buffer = allocate_cbuffer(json.length + 256)
78
+ output_buffer = allocate_cbuffer(json.bytesize)
140
79
 
141
80
  result = DecryptFromJson(partition_id_buffer, data_buffer, output_buffer)
142
81
  Error.check_result!(result, 'DecryptFromJson failed')
143
82
 
144
83
  cbuffer_to_string(output_buffer)
84
+ ensure
85
+ [partition_id_buffer, data_buffer, output_buffer].map(&:free)
86
+ end
87
+
88
+ # Stop the Asherah instance
89
+ def shutdown
90
+ Shutdown()
91
+ end
92
+
93
+ private
94
+
95
+ def estimate_buffer(data_bytesize, partition_bytesize)
96
+ ESTIMATED_ENVELOPE_OVERHEAD +
97
+ @intermediated_key_overhead_bytesize +
98
+ partition_bytesize +
99
+ ((data_bytesize + ESTIMATED_ENCRYPTION_OVERHEAD) * BASE64_OVERHEAD)
145
100
  end
146
101
  end
147
102
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asherah
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.beta.2
4
+ version: 0.3.0
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - GoDaddy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-14 00:00:00.000000000 Z
11
+ date: 2022-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cobhan
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.1.2
19
+ version: 0.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.1.2
26
+ version: 0.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: dotenv
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -117,10 +117,7 @@ files:
117
117
  - asherah.gemspec
118
118
  - lib/asherah.rb
119
119
  - lib/asherah/config.rb
120
- - lib/asherah/data_row_record.rb
121
- - lib/asherah/envelope_key_record.rb
122
120
  - lib/asherah/error.rb
123
- - lib/asherah/key_meta.rb
124
121
  - lib/asherah/native/libasherah-x64.dylib
125
122
  - lib/asherah/version.rb
126
123
  homepage: https://github.com/godaddy/asherah-ruby
@@ -142,9 +139,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
139
  version: 2.5.0
143
140
  required_rubygems_version: !ruby/object:Gem::Requirement
144
141
  requirements:
145
- - - ">"
142
+ - - ">="
146
143
  - !ruby/object:Gem::Version
147
- version: 1.3.1
144
+ version: '0'
148
145
  requirements: []
149
146
  rubygems_version: 3.3.7
150
147
  signing_key:
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Asherah
4
- # DataRowRecord contains the encrypted key and data, as well as the information
5
- # required to decrypt the key encryption key. This object data should be stored
6
- # in your data persistence as it's required to decrypt data.
7
- class DataRowRecord
8
- attr_reader :data, :key
9
-
10
- # Initializes a new DataRowRecord
11
- #
12
- # @param data [String]
13
- # @param key [EnvelopeKeyRecord]
14
- # @return DataRowRecord
15
- def initialize(data:, key:)
16
- @data = data
17
- @key = key
18
- end
19
- end
20
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Asherah
4
- # EnvelopeKeyRecord represents an encrypted key and is the data structure used
5
- # to persist the key in the key table. It also contains the meta data
6
- # of the key used to encrypt it.
7
- class EnvelopeKeyRecord
8
- attr_reader :encrypted_key, :created, :parent_key_meta
9
-
10
- # Initializes a new EnvelopeKeyRecord
11
- #
12
- # @param encrypted_key [String]
13
- # @param created [Integer]
14
- # @param parent_key_meta [KeyMeta]
15
- # @return EnvelopeKeyRecord
16
- def initialize(encrypted_key:, created:, parent_key_meta:)
17
- @encrypted_key = encrypted_key
18
- @created = created
19
- @parent_key_meta = parent_key_meta
20
- end
21
- end
22
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Asherah
4
- # KeyMeta contains the `id` and `created` timestamp for an encryption key.
5
- class KeyMeta
6
- attr_reader :id, :created
7
-
8
- # Initializes a new KeyMeta
9
- #
10
- # @param id [String]
11
- # @param created [Integer]
12
- # @return KeyMeta
13
- def initialize(id:, created:)
14
- @id = id
15
- @created = created
16
- end
17
- end
18
- end