asherah 0.1.0.beta.1-aarch64-linux → 0.3.0-aarch64-linux
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 +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.so +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: ef6d062e4ed676c66a72dba500d4376801b33199da28e69eb2e62f34dae62a40
|
4
|
+
data.tar.gz: 2909ca407f9d1954e68232122373baa30c3a33095d65b890d996061902bcc136
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 888f1d7c7534919bd79c70def643abd712e01b06808a78b4fc7017e0a0e0e841c267921635cf8beacf0bc7e99b986aa64e7258d2313728c02784c878d0cc5502
|
7
|
+
data.tar.gz: 18d76b1c06ed638fa06f15dbfbed49cca82c2ae19d31d0c5ff1968da854dce4b43b724cc267638e422c02db0b1692fd255deb360531418ac571e30b7a91a6d07
|
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: aarch64-linux
|
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.so
|
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: []
|