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

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 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