asherah 0.1.0.beta.1-arm64-darwin → 0.3.0-arm64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -7
- data/CHANGELOG.md +29 -2
- data/Gemfile +1 -3
- data/README.md +53 -9
- data/Rakefile +49 -25
- data/asherah.gemspec +6 -1
- data/lib/asherah/config.rb +102 -0
- data/lib/asherah/error.rb +21 -12
- data/lib/asherah/native/libasherah-arm64.dylib +0 -0
- data/lib/asherah/version.rb +1 -1
- data/lib/asherah.rb +71 -156
- metadata +81 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a43b4d34ccce682cf20e8e0154704be1e88f43fd83243143b1eb29cb184e5e1
|
4
|
+
data.tar.gz: 4e1f4ba3d4f67096204bc126eea95e2dcc50666ecf1dc4d3e4f2dac2108b19e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ff13c55e0d1eee27ed301a854e353fe0edc7acdbe99f9da41a1e215ee64f7311353bc45f89f1ad652508545e74e9f1949e92e50e9dd6d41ebe8c2bea47ef1c6
|
7
|
+
data.tar.gz: 63dab48dfb85fe4e794dc5a5431cf1a7e5abc2f27ff62a90d9e7cec7939e85e24e04ccdd14107274a341f9f7b1020867bcae41b93ef0ce8d4064d48bf544bc3e
|
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
|
@@ -26,14 +27,8 @@ Style/MultilineBlockChain:
|
|
26
27
|
Style/BlockDelimiters:
|
27
28
|
Enabled: false
|
28
29
|
|
29
|
-
Style/HashAsLastArrayItem:
|
30
|
-
Enabled: false
|
31
|
-
|
32
30
|
Metrics/AbcSize:
|
33
31
|
Enabled: false
|
34
32
|
|
35
|
-
|
36
|
-
Enabled: false
|
37
|
-
|
38
|
-
Metrics/ModuleLength:
|
33
|
+
Style/GuardClause:
|
39
34
|
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [0.
|
3
|
+
## [0.3.0] - 2022-03-22
|
4
4
|
|
5
|
-
-
|
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
|
20
|
+
|
21
|
+
## [0.1.0.beta2] - 2022-03-14
|
22
|
+
|
23
|
+
- Add smoke tests for native gems
|
24
|
+
- Change to use `SetupJson` instead of `Setup`
|
25
|
+
- Update config options to make them consistent with Asherah Go
|
26
|
+
- Add `shutdown`
|
27
|
+
- Add `encrypt_to_json` and `decrypt_from_json`
|
28
|
+
- Add coverage report
|
29
|
+
|
30
|
+
## [0.1.0.beta1] - 2022-03-07
|
31
|
+
|
32
|
+
- Initial proof of concept
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
# Asherah
|
2
2
|
|
3
|
-
|
3
|
+
Asherah is a Ruby wrapper around [Asherah Go](https://github.com/godaddy/asherah) application-layer encryption SDK that provides advanced encryption features and defense in depth against compromise. It uses a technique known as "envelope encryption" and supports cloud-agnostic data storage and key management.
|
4
4
|
|
5
|
-
|
5
|
+
Check out the following documentation to get more familiar with its concepts:
|
6
|
+
|
7
|
+
- [Design and Architecture](https://github.com/godaddy/asherah/blob/master/docs/DesignAndArchitecture.md)
|
8
|
+
- [Key Caching](https://github.com/godaddy/asherah/blob/master/docs/KeyCaching.md)
|
9
|
+
- [Key Management Service](https://github.com/godaddy/asherah/blob/master/docs/KeyManagementService.md)
|
10
|
+
- [Metastore](https://github.com/godaddy/asherah/blob/master/docs/Metastore.md)
|
11
|
+
- [System Requirements](https://github.com/godaddy/asherah/blob/master/docs/SystemRequirements.md)
|
6
12
|
|
7
13
|
## Installation
|
8
14
|
|
@@ -12,17 +18,44 @@ Add this line to your application's Gemfile:
|
|
12
18
|
gem 'asherah'
|
13
19
|
```
|
14
20
|
|
15
|
-
|
16
|
-
|
17
|
-
|
21
|
+
```bash
|
22
|
+
bundle install
|
23
|
+
```
|
18
24
|
|
19
25
|
Or install it yourself as:
|
20
26
|
|
21
|
-
|
27
|
+
```bash
|
28
|
+
gem install asherah
|
29
|
+
```
|
22
30
|
|
23
31
|
## Usage
|
24
32
|
|
25
|
-
|
33
|
+
Configure Asherah:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
Asherah.configure do |config|
|
37
|
+
config.kms = 'static'
|
38
|
+
config.metastore = 'memory'
|
39
|
+
config.service_name = 'service'
|
40
|
+
config.product_id = 'product'
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Encrypt some data for a `partition_id`
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
partition_id = 'user_1'
|
48
|
+
data = 'Some PII data'
|
49
|
+
data_row_record_json = Asherah.encrypt(partition_id, data)
|
50
|
+
puts data_row_record_json
|
51
|
+
```
|
52
|
+
|
53
|
+
Decrypt `data_row_record_json`
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
decrypted_data = Asherah.decrypt(partition_id, data_row_record_json)
|
57
|
+
puts decrypted_data
|
58
|
+
```
|
26
59
|
|
27
60
|
## Development
|
28
61
|
|
@@ -32,8 +65,19 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
65
|
|
33
66
|
## Contributing
|
34
67
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
68
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/godaddy/asherah-ruby.
|
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
|
+
```
|
36
80
|
|
37
81
|
## License
|
38
82
|
|
39
|
-
The gem is available as open source under the terms of the [MIT License](
|
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,12 +12,26 @@ 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'],
|
19
19
|
'aarch64-linux' => ['libasherah-arm64.so'],
|
20
20
|
'arm64-darwin' => ['libasherah-arm64.dylib']
|
21
|
-
}
|
21
|
+
}.freeze
|
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
|
22
35
|
|
23
36
|
def native_build(platform, native_files)
|
24
37
|
puts "Building gem for #{platform}"
|
@@ -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
|
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,30 +60,29 @@ 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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
72
|
+
package = Gem::Package.build(gemspec)
|
60
73
|
FileUtils.mv package, File.join(pkg_dir, package)
|
61
74
|
end
|
62
75
|
end
|
63
76
|
|
64
|
-
|
65
77
|
namespace :native do
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
native_build(platform, native_files)
|
71
|
-
end
|
78
|
+
desc 'Build all native gems'
|
79
|
+
task :build do
|
80
|
+
DISTRIBUTIONS.each do |platform, native_files|
|
81
|
+
native_build(platform, native_files)
|
72
82
|
end
|
83
|
+
end
|
73
84
|
|
85
|
+
namespace :build do
|
74
86
|
DISTRIBUTIONS.each do |platform, native_files|
|
75
87
|
desc "Build native gem for #{platform}"
|
76
88
|
task :"#{platform}" do
|
@@ -79,19 +91,31 @@ namespace :native do
|
|
79
91
|
end
|
80
92
|
end
|
81
93
|
|
82
|
-
namespace :
|
83
|
-
|
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
|
84
100
|
|
85
|
-
|
86
|
-
|
101
|
+
desc 'Build native gem for current platform'
|
102
|
+
task :build do
|
103
|
+
native_build(current_platform, DISTRIBUTIONS[current_platform])
|
104
|
+
end
|
87
105
|
|
88
|
-
desc
|
89
|
-
task :
|
106
|
+
desc 'Smoke test native gem for current platform'
|
107
|
+
task smoke: :build do
|
108
|
+
platform = current_platform
|
90
109
|
gemspec = Bundler.load_gemspec('asherah.gemspec')
|
91
110
|
gemspec.platform = Gem::Platform.new(platform)
|
92
111
|
|
112
|
+
sh('gem uninstall asherah')
|
93
113
|
sh("gem install pkg/#{gemspec.file_name}")
|
94
|
-
sh(
|
114
|
+
sh('ruby spec/smoke_test.rb')
|
95
115
|
end
|
96
116
|
end
|
97
117
|
end
|
118
|
+
|
119
|
+
task :version do
|
120
|
+
puts Asherah::VERSION
|
121
|
+
end
|
data/asherah.gemspec
CHANGED
@@ -34,5 +34,10 @@ 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.
|
37
|
+
spec.add_dependency 'cobhan', '~> 0.2.0'
|
38
|
+
spec.add_development_dependency 'dotenv', '~> 2.7.6'
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.10.0'
|
40
|
+
spec.add_development_dependency 'rubocop', '~> 1.7'
|
41
|
+
spec.add_development_dependency 'simplecov', '~> 0.21.2'
|
42
|
+
spec.add_development_dependency 'simplecov-console', '~> 0.9.1'
|
38
43
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Asherah
|
6
|
+
# @attr [String] service_name, The name of this service
|
7
|
+
# @attr [String] product_id, The name of the product that owns this service
|
8
|
+
# @attr [String] kms, The master key management service (static or aws)
|
9
|
+
# @attr [String] metastore, The type of metastore for persisting keys (rdbms, dynamodb, memory)
|
10
|
+
# @attr [String] connection_string, The database connection string (required when metastore is rdbms)
|
11
|
+
# @attr [String] replica_read_consistency, For Aurora sessions using write forwarding (eventual, global, session)
|
12
|
+
# @attr [String] dynamo_db_endpoint, An optional endpoint URL (for dynamodb metastore)
|
13
|
+
# @attr [String] dynamo_db_region, The AWS region for DynamoDB requests (for dynamodb metastore)
|
14
|
+
# @attr [String] dynamo_db_table_name, The table name for DynamoDB (for dynamodb metastore)
|
15
|
+
# @attr [Boolean] enable_region_suffix, Configure the metastore to use regional suffixes (for dynamodb metastore)
|
16
|
+
# @attr [String] region_map, List of key-value pairs in the form of REGION1=ARN1[,REGION2=ARN2] (required for aws kms)
|
17
|
+
# @attr [String] preferred_region, The preferred AWS region (required for aws kms)
|
18
|
+
# @attr [Integer] session_cache_max_size, The maximum number of sessions to cache
|
19
|
+
# @attr [Integer] session_cache_duration, The amount of time in seconds a session will remain cached
|
20
|
+
# @attr [Integer] expire_after, The amount of time in seconds a key is considered valid
|
21
|
+
# @attr [Integer] check_interval, The amount of time in seconds before cached keys are considered stale
|
22
|
+
# @attr [Boolean] enable_session_caching, Enable shared session caching
|
23
|
+
# @attr [Boolean] verbose, Enable verbose logging output
|
24
|
+
class Config
|
25
|
+
MAPPING = {
|
26
|
+
service_name: :ServiceName,
|
27
|
+
product_id: :ProductID,
|
28
|
+
kms: :KMS,
|
29
|
+
metastore: :Metastore,
|
30
|
+
connection_string: :ConnectionString,
|
31
|
+
replica_read_consistency: :ReplicaReadConsistency,
|
32
|
+
dynamo_db_endpoint: :DynamoDBEndpoint,
|
33
|
+
dynamo_db_region: :DynamoDBRegion,
|
34
|
+
dynamo_db_table_name: :DynamoDBTableName,
|
35
|
+
enable_region_suffix: :EnableRegionSuffix,
|
36
|
+
region_map: :RegionMap,
|
37
|
+
preferred_region: :PreferredRegion,
|
38
|
+
session_cache_max_size: :SessionCacheMaxSize,
|
39
|
+
session_cache_duration: :SessionCacheDuration,
|
40
|
+
enable_session_caching: :EnableSessionCaching,
|
41
|
+
expire_after: :ExpireAfter,
|
42
|
+
check_interval: :CheckInterval,
|
43
|
+
verbose: :Verbose
|
44
|
+
}.freeze
|
45
|
+
|
46
|
+
KMS_TYPES = ['static', 'aws'].freeze
|
47
|
+
METASTORE_TYPES = ['rdbms', 'dynamodb', 'memory'].freeze
|
48
|
+
|
49
|
+
attr_accessor(*MAPPING.keys)
|
50
|
+
|
51
|
+
def validate!
|
52
|
+
validate_service_name
|
53
|
+
validate_product_id
|
54
|
+
validate_kms
|
55
|
+
validate_metastore
|
56
|
+
validate_kms_attributes
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_json(*args)
|
60
|
+
config = {}.tap do |c|
|
61
|
+
MAPPING.each_pair do |our_key, their_key|
|
62
|
+
value = public_send(our_key)
|
63
|
+
c[their_key] = value unless value.nil?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
JSON.generate(config, *args)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def validate_service_name
|
73
|
+
raise Error::ConfigError, 'config.service_name not set' if service_name.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_product_id
|
77
|
+
raise Error::ConfigError, 'config.product_id not set' if product_id.nil?
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_kms
|
81
|
+
raise Error::ConfigError, 'config.kms not set' if kms.nil?
|
82
|
+
unless KMS_TYPES.include?(kms)
|
83
|
+
raise Error::ConfigError, "config.kms must be one of these: #{KMS_TYPES.join(', ')}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def validate_metastore
|
88
|
+
raise Error::ConfigError, 'config.metastore not set' if metastore.nil?
|
89
|
+
unless METASTORE_TYPES.include?(metastore)
|
90
|
+
raise Error::ConfigError, "config.metastore must be one of these: #{METASTORE_TYPES.join(', ')}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def validate_kms_attributes
|
95
|
+
if kms == 'aws'
|
96
|
+
raise Error::ConfigError, 'config.region_map not set' if region_map.nil?
|
97
|
+
raise Error::ConfigError, 'config.region_map must be a Hash' unless region_map.is_a?(Hash)
|
98
|
+
raise Error::ConfigError, 'config.preferred_region not set' if preferred_region.nil?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/asherah/error.rb
CHANGED
@@ -1,21 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Asherah
|
4
|
+
# Asherah Error converts the error code to error message
|
3
5
|
module Error
|
4
|
-
|
6
|
+
ConfigError = Class.new(StandardError)
|
7
|
+
NotInitialized = Class.new(StandardError)
|
8
|
+
AlreadyInitialized = Class.new(StandardError)
|
9
|
+
GetSessionFailed = Class.new(StandardError)
|
10
|
+
EncryptFailed = Class.new(StandardError)
|
11
|
+
DecryptFailed = Class.new(StandardError)
|
12
|
+
BadConfig = Class.new(StandardError)
|
5
13
|
|
6
14
|
CODES = {
|
7
|
-
-100 =>
|
8
|
-
-101 =>
|
9
|
-
-102 =>
|
10
|
-
-103 =>
|
11
|
-
-104 =>
|
12
|
-
|
15
|
+
-100 => NotInitialized,
|
16
|
+
-101 => AlreadyInitialized,
|
17
|
+
-102 => GetSessionFailed,
|
18
|
+
-103 => EncryptFailed,
|
19
|
+
-104 => DecryptFailed,
|
20
|
+
-105 => BadConfig
|
21
|
+
}.freeze
|
13
22
|
|
14
|
-
def self.check_result!(
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
23
|
+
def self.check_result!(result, message)
|
24
|
+
return unless result.negative?
|
25
|
+
|
26
|
+
error_class = Error::CODES.fetch(result, StandardError)
|
27
|
+
raise error_class, "#{message} (#{result})"
|
19
28
|
end
|
20
29
|
end
|
21
30
|
end
|
Binary file
|
data/lib/asherah/version.rb
CHANGED
data/lib/asherah.rb
CHANGED
@@ -1,187 +1,102 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'asherah/version'
|
4
|
+
require 'asherah/config'
|
4
5
|
require 'asherah/error'
|
5
6
|
require 'cobhan'
|
6
7
|
|
7
|
-
# Asherah
|
8
|
-
#
|
9
|
-
# `data_row_record` contains the encrypted key and provided data, as well as the information
|
10
|
-
# required to decrypt the key encryption key. This struct should be stored in your
|
11
|
-
# data persistence as it's required to decrypt data.
|
12
|
-
#
|
13
|
-
# data_row_record [Hash]
|
14
|
-
# key [Hash], envelope_key_record
|
15
|
-
# data [String]
|
16
|
-
#
|
17
|
-
# `envelope_key_record` represents an encrypted key and is the data structure used
|
18
|
-
# to persist the key in our key table. It also contains the meta data
|
19
|
-
# of the key used to encrypt it.
|
20
|
-
#
|
21
|
-
# envelope_key_record [Hash]
|
22
|
-
# created [Integer]
|
23
|
-
# encrypted_key [String]
|
24
|
-
# parent_key_meta [Hash], key_meta
|
25
|
-
#
|
26
|
-
# `key_meta` contains the `id` and `created` timestamp for an encryption key.
|
27
|
-
#
|
28
|
-
# key_meta [Hash]
|
29
|
-
# id [String]
|
30
|
-
# created [Integer]
|
8
|
+
# Asherah is a Ruby wrapper around Asherah Go application-layer encryption SDK.
|
31
9
|
module Asherah
|
32
10
|
extend Cobhan
|
33
11
|
|
34
12
|
LIB_ROOT_PATH = File.expand_path('asherah/native', __dir__)
|
35
13
|
load_library(LIB_ROOT_PATH, 'libasherah', [
|
36
|
-
[
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
:pointer, :pointer, :pointer, :pointer, :int32, :int32, :int32
|
41
|
-
],
|
42
|
-
:int32
|
43
|
-
],
|
44
|
-
[:Encrypt, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int32],
|
45
|
-
[:Decrypt, [:pointer, :pointer, :pointer, :int64, :pointer, :int64, :pointer], :int32]
|
14
|
+
[:SetupJson, [:pointer], :int32],
|
15
|
+
[:EncryptToJson, [:pointer, :pointer, :pointer], :int32],
|
16
|
+
[:DecryptFromJson, [:pointer, :pointer, :pointer], :int32],
|
17
|
+
[:Shutdown, [], :void]
|
46
18
|
].freeze)
|
47
19
|
|
20
|
+
ESTIMATED_ENCRYPTION_OVERHEAD = 48
|
21
|
+
ESTIMATED_ENVELOPE_OVERHEAD = 185
|
22
|
+
BASE64_OVERHEAD = 1.34
|
23
|
+
|
48
24
|
class << self
|
49
|
-
#
|
25
|
+
# Configures Asherah
|
50
26
|
#
|
51
|
-
# @
|
52
|
-
# @
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
# @param session_cache [Boolean]
|
64
|
-
# @param debug_output [Boolean]
|
65
|
-
def setup(
|
66
|
-
kms_type:,
|
67
|
-
metastore:,
|
68
|
-
service_name:,
|
69
|
-
product_id:,
|
70
|
-
rdbms_connection_string: '',
|
71
|
-
dynamo_db_endpoint: '',
|
72
|
-
dynamo_db_region: '',
|
73
|
-
dynamo_db_table_name: '',
|
74
|
-
enable_region_suffix: false,
|
75
|
-
preferred_region: '',
|
76
|
-
region_map: '',
|
77
|
-
verbose: false,
|
78
|
-
session_cache: false,
|
79
|
-
debug_output: false
|
80
|
-
)
|
81
|
-
kms_type_buffer = string_to_cbuffer(kms_type)
|
82
|
-
metastore_buffer = string_to_cbuffer(metastore)
|
83
|
-
rdbms_connection_string_buffer = string_to_cbuffer(rdbms_connection_string)
|
84
|
-
dynamo_db_endpoint_buffer = string_to_cbuffer(dynamo_db_endpoint)
|
85
|
-
dynamo_db_region_buffer = string_to_cbuffer(dynamo_db_region)
|
86
|
-
dynamo_db_table_name_buffer = string_to_cbuffer(dynamo_db_table_name)
|
87
|
-
enable_region_suffix_int = enable_region_suffix ? 1 : 0
|
88
|
-
service_name_buffer = string_to_cbuffer(service_name)
|
89
|
-
product_id_buffer = string_to_cbuffer(product_id)
|
90
|
-
preferred_region_buffer = string_to_cbuffer(preferred_region)
|
91
|
-
region_map_buffer = string_to_cbuffer(region_map)
|
92
|
-
verbose_int = verbose ? 1 : 0
|
93
|
-
session_cache_int = session_cache ? 1 : 0
|
94
|
-
debug_output_int = debug_output ? 1 : 0
|
95
|
-
|
96
|
-
result = Setup(
|
97
|
-
kms_type_buffer,
|
98
|
-
metastore_buffer,
|
99
|
-
rdbms_connection_string_buffer,
|
100
|
-
dynamo_db_endpoint_buffer,
|
101
|
-
dynamo_db_region_buffer,
|
102
|
-
dynamo_db_table_name_buffer,
|
103
|
-
enable_region_suffix_int,
|
104
|
-
service_name_buffer,
|
105
|
-
product_id_buffer,
|
106
|
-
preferred_region_buffer,
|
107
|
-
region_map_buffer,
|
108
|
-
verbose_int,
|
109
|
-
session_cache_int,
|
110
|
-
debug_output_int
|
111
|
-
)
|
112
|
-
|
113
|
-
Error.check_result!('setup', result)
|
27
|
+
# @yield [Config]
|
28
|
+
# @return [void]
|
29
|
+
def configure
|
30
|
+
config = Config.new
|
31
|
+
yield config
|
32
|
+
config.validate!
|
33
|
+
@intermediated_key_overhead_bytesize = config.product_id.bytesize + config.service_name.bytesize
|
34
|
+
|
35
|
+
config_buffer = string_to_cbuffer(config.to_json)
|
36
|
+
|
37
|
+
result = SetupJson(config_buffer)
|
38
|
+
Error.check_result!(result, 'SetupJson failed')
|
114
39
|
end
|
115
40
|
|
116
|
-
# Encrypts data for a given partition_id
|
41
|
+
# Encrypts data for a given partition_id and returns DataRowRecord in JSON format.
|
42
|
+
#
|
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.
|
46
|
+
#
|
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.
|
117
52
|
#
|
118
53
|
# @param partition_id [String]
|
119
54
|
# @param data [String]
|
120
|
-
# @return [
|
55
|
+
# @return [String], DataRowRecord in JSON format
|
121
56
|
def encrypt(partition_id, data)
|
122
57
|
partition_id_buffer = string_to_cbuffer(partition_id)
|
123
58
|
data_buffer = string_to_cbuffer(data)
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
output_encrypted_data_buffer,
|
134
|
-
output_encrypted_key_buffer,
|
135
|
-
output_created_buffer,
|
136
|
-
output_parent_key_id_buffer,
|
137
|
-
output_parent_key_created_buffer
|
138
|
-
)
|
139
|
-
|
140
|
-
Error.check_result!('encrypt', result)
|
141
|
-
|
142
|
-
parent_key_id = cbuffer_to_string(output_parent_key_id_buffer)
|
143
|
-
|
144
|
-
{
|
145
|
-
data: cbuffer_to_string(output_encrypted_data_buffer),
|
146
|
-
key: {
|
147
|
-
encrypted_key: cbuffer_to_string(output_encrypted_key_buffer),
|
148
|
-
created: buffer_to_int(output_created_buffer),
|
149
|
-
parent_key_meta: {
|
150
|
-
id: parent_key_id,
|
151
|
-
created: buffer_to_int(output_parent_key_created_buffer)
|
152
|
-
}
|
153
|
-
}
|
154
|
-
}
|
59
|
+
estimated_buffer_bytesize = estimate_buffer(data.bytesize, partition_id.bytesize)
|
60
|
+
output_buffer = allocate_cbuffer(estimated_buffer_bytesize)
|
61
|
+
|
62
|
+
result = EncryptToJson(partition_id_buffer, data_buffer, output_buffer)
|
63
|
+
Error.check_result!(result, 'EncryptToJson failed')
|
64
|
+
|
65
|
+
cbuffer_to_string(output_buffer)
|
66
|
+
ensure
|
67
|
+
[partition_id_buffer, data_buffer, output_buffer].map(&:free)
|
155
68
|
end
|
156
69
|
|
157
|
-
# Decrypts a
|
70
|
+
# Decrypts a DataRowRecord in JSON format for a partition_id and returns decrypted data.
|
158
71
|
#
|
159
72
|
# @param partition_id [String]
|
160
|
-
# @param
|
161
|
-
# @return [String]
|
162
|
-
def decrypt(partition_id,
|
73
|
+
# @param json [String], DataRowRecord in JSON format
|
74
|
+
# @return [String], Decrypted data
|
75
|
+
def decrypt(partition_id, json)
|
163
76
|
partition_id_buffer = string_to_cbuffer(partition_id)
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
77
|
+
data_buffer = string_to_cbuffer(json)
|
78
|
+
output_buffer = allocate_cbuffer(json.bytesize)
|
79
|
+
|
80
|
+
result = DecryptFromJson(partition_id_buffer, data_buffer, output_buffer)
|
81
|
+
Error.check_result!(result, 'DecryptFromJson failed')
|
82
|
+
|
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)
|
185
100
|
end
|
186
101
|
end
|
187
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: arm64-darwin
|
6
6
|
authors:
|
7
7
|
- GoDaddy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
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,84 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
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.
|
26
|
+
version: 0.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dotenv
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.7.6
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.7.6
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.10.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.10.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.21.2
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.21.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov-console
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.9.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.9.1
|
27
97
|
description: |
|
28
98
|
Asherah is an application-layer encryption SDK that provides advanced
|
29
99
|
encryption features and defense in depth against compromise.
|
@@ -46,6 +116,7 @@ files:
|
|
46
116
|
- SECURITY.md
|
47
117
|
- asherah.gemspec
|
48
118
|
- lib/asherah.rb
|
119
|
+
- lib/asherah/config.rb
|
49
120
|
- lib/asherah/error.rb
|
50
121
|
- lib/asherah/native/libasherah-arm64.dylib
|
51
122
|
- lib/asherah/version.rb
|
@@ -57,7 +128,7 @@ metadata:
|
|
57
128
|
source_code_uri: https://github.com/godaddy/asherah-ruby
|
58
129
|
changelog_uri: https://github.com/godaddy/asherah-ruby/blob/main/CHANGELOG.md
|
59
130
|
rubygems_mfa_required: 'true'
|
60
|
-
post_install_message:
|
131
|
+
post_install_message:
|
61
132
|
rdoc_options: []
|
62
133
|
require_paths:
|
63
134
|
- lib
|
@@ -68,12 +139,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
139
|
version: 2.5.0
|
69
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
141
|
requirements:
|
71
|
-
- - "
|
142
|
+
- - ">="
|
72
143
|
- !ruby/object:Gem::Version
|
73
|
-
version:
|
144
|
+
version: '0'
|
74
145
|
requirements: []
|
75
|
-
rubygems_version: 3.3.
|
76
|
-
signing_key:
|
146
|
+
rubygems_version: 3.3.7
|
147
|
+
signing_key:
|
77
148
|
specification_version: 4
|
78
149
|
summary: Application Layer Encryption SDK
|
79
150
|
test_files: []
|