hydan 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b9a7ad17b289c67ab39aa32e25df5571fa67fc18
4
+ data.tar.gz: 7521911f20b2c469fca0684cca905bc49bd55012
5
+ SHA512:
6
+ metadata.gz: 183654b57e053c76526841781086fbb3bf77ba85a2ce8c0afc264aafeff51de1a1e2312f21a013b56b2adf641f0f516ec6ca5ebc5b25f5138435a6455768eaeb
7
+ data.tar.gz: 7233ecf3068a7d1ae6ecd584000a83c6b361c1e154bb5e1d9d1c00b0fe55200e3b1a0043172b67472ea45d49ca3db1d3b8c0e0709099338c6816596d69a24fde
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.swp
11
+ .DS_Store
12
+ *.env
@@ -0,0 +1,6 @@
1
+ - repo: git://github.com/pre-commit/pre-commit-hooks
2
+ sha: ff65d01841ad012d0a9aa1dc451fc4539d8b7baf
3
+ hooks:
4
+ - id: check-yaml
5
+ - id: detect-aws-credentials
6
+ - id: trailing-whitespace
data/Dockerfile.tpl ADDED
@@ -0,0 +1,10 @@
1
+ FROM ruby:#VERSION#
2
+ MAINTAINER "rxacevedo@fastmail.com"
3
+
4
+ COPY . /usr/src/app
5
+ WORKDIR /usr/src/app
6
+
7
+ RUN bundle install
8
+ RUN rake install
9
+
10
+ ENTRYPOINT ["hydan"]
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hydan.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,48 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hydan (0.1.1)
5
+ aws-sdk (~> 2)
6
+ gibberish
7
+ thor
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ aws-sdk (2.2.30)
13
+ aws-sdk-resources (= 2.2.30)
14
+ aws-sdk-core (2.2.30)
15
+ jmespath (~> 1.0)
16
+ aws-sdk-resources (2.2.30)
17
+ aws-sdk-core (= 2.2.30)
18
+ coderay (1.1.1)
19
+ gibberish (2.0.0)
20
+ jmespath (1.1.3)
21
+ method_source (0.8.2)
22
+ minitest (5.8.4)
23
+ pry (0.10.3)
24
+ coderay (~> 1.1.0)
25
+ method_source (~> 0.8.1)
26
+ slop (~> 3.4)
27
+ pry-doc (0.8.0)
28
+ pry (~> 0.9)
29
+ yard (~> 0.8)
30
+ rake (10.5.0)
31
+ slop (3.6.0)
32
+ thor (0.19.1)
33
+ yard (0.8.7.6)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ bundler (~> 1.11)
40
+ hydan!
41
+ minitest (~> 5.0)
42
+ pry (~> 0.10)
43
+ pry-doc (>= 0.6.0)
44
+ rake (~> 10.0)
45
+ yard
46
+
47
+ BUNDLED WITH
48
+ 1.11.2
data/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # Hydan
2
+
3
+ Hydan is a command-line utility for encrypting and decrypting text and/or files. In addition to local crypto operations, Hydan can also defer to Amazon KMS for symmetric master keys. S3 uploads/downloads are also supported, and can leverage KMS for encryption/decryption.
4
+
5
+ ## TODO:
6
+
7
+ - [ ] Support multi-part uploads for S3
8
+ - [ ] Support SSE for S3 uploads
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'hydan'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install hydan
25
+
26
+ ## Disclaimer
27
+
28
+ Hydan is open-source software - **USE AT YOUR OWN RISK!** The authors and all affiliates assume no responsibility for issues encountered with the use of of this software.
29
+
30
+ ## Usage
31
+
32
+ ### Local text encryption
33
+
34
+ Local text encryption returns a JSON object containing the cihpertext and randomly-generated data key. Plaintext can be piped into STDIN or passed on the CLI via the `--text` flag.
35
+
36
+ ```
37
+ # We'll grab 256 random bits for the master key
38
+ KEY=$(head -c 32 /dev/urandom | base64)
39
+ echo 'A secret on STDIN' | hydan encrypt --master-key $KEY
40
+ {
41
+ "ciphertext": {
42
+ "v": 1,
43
+ "adata": "",
44
+ "ks": 256,
45
+ "ct": "8VmGeR6+rtznK6Lu8vmr99PFmbxfu6FcyzWyiU17",
46
+ "ts": 96,
47
+ "mode": "gcm",
48
+ "cipher": "aes",
49
+ "iter": 100000,
50
+ "iv": "8Pj1RuenaRqV5BRc",
51
+ "salt": "mXfzMTw89lE="
52
+ },
53
+ "data_key": "eyJ2IjoxLCJhZGF0YSI6IiIsImtzIjoyNTYsImN0IjoiVlVDclRLUTV2WVpBMGFuTW9NTUQzWS9OQ0NYUkF0SWFpc3JYcFI1THVraHptUE1WeTVqRzBsbFJsM1k9IiwidHMiOjk2LCJtb2RlIjoiZ2NtIiwiY2lwaGVyIjoiYWVzIiwiaXRlciI6MTAwMDAwLCJpdiI6ImRUeTBPVUt2a3plaThkdnEiLCJzYWx0Ijoib1BQTXF2U1ZCN2c9In0="
54
+ }
55
+ ```
56
+
57
+ ### Local decryption
58
+ ```
59
+ KEY=$(head -c 32 /dev/urandom | base64)
60
+ echo 'The Krabby Patty secret recipe IS...' | hydan encrypt --master-key $KEY | hydan decrypt --master-key $KEY
61
+ The Krabby Patty secret recipe IS...
62
+
63
+ hydan encrypt --master-key $KEY --text 'This also works' | hydan decrypt --master-key $KEY
64
+ This also works
65
+ ```
66
+
67
+ #### Env files
68
+ A common use case (actually, the reason that this utility was even written) for setting up credentials is through environment variables. To accomodate this, `hydan` supports `--env-formatted` text input. When this flag is passed in, K/V pairs are parsed from each line, and the value (V) is encrypted. This allows for a file to be partially encrypted in a way that hides sensitive information, while still allowing an administrator or operator to understand what the file is for.
69
+
70
+ ```
71
+ KEY=$(head -c 32 /dev/urandom | base64)
72
+ cat test.env
73
+ FOO=bar
74
+ BAR=baz
75
+ BAZ=bat
76
+ A=B
77
+ ENV=ENV
78
+ K=V
79
+
80
+ hydan encrypt --env-formatted --master-key $KEY < test.env
81
+ FOO={"ciphertext":{"v":1,"adata":"","ks":256,"ct":"fnu8Ulyr5JLQArNp5rLz","ts":96,"mode":"gcm","cipher":"aes","iter":100000,"iv":"MOZzAZ/9qtHMCr/t","salt":"37WkVaQQxDA="},"data_key":"eyJ2IjoxLCJhZGF0YSI6IiIsImtzIjoyNTYsImN0IjoiMjFjZ21kM21PbUxBL20xdUt1bDJHNXV5VUhkaXFLQlZhSGlCQ2NzVnczbG5mUnY0Y05SSHRRMFFWVUE9IiwidHMiOjk2LCJtb2RlIjoiZ2NtIiwiY2lwaGVyIjoiYWVzIiwiaXRlciI6MTAwMDAwLCJpdiI6IkNRSkNJanlKVW9pR0kzbHQiLCJzYWx0IjoibS94a2trSm85Nzg9In0="}
82
+ BAR={"ciphertext":{"v":1,"adata":"","ks":256,"ct":"F9oTm34xCj5Ke68hB+rL","ts":96,"mode":"gcm","cipher":"aes","iter":100000,"iv":"uXP2BC9wyCyJiFy6","salt":"DLDWXIxsbv8="},"data_key":"eyJ2IjoxLCJhZGF0YSI6IiIsImtzIjoyNTYsImN0IjoiYWRRdC9reFQzS2FwSG9FWFlzclJ6bmhqdlcxYVVGdWtQd0xRZXJZTUdTMDF0WFY1RSsyRkRBZndndDA9IiwidHMiOjk2LCJtb2RlIjoiZ2NtIiwiY2lwaGVyIjoiYWVzIiwiaXRlciI6MTAwMDAwLCJpdiI6Ii9SbnFWWkZTR0EwQkw0UEEiLCJzYWx0IjoiSHYxeEd0eTZLcTQ9In0="}
83
+ BAZ={"ciphertext":{"v":1,"adata":"","ks":256,"ct":"VZ3qtRrRYVRIhJ3qIyku","ts":96,"mode":"gcm","cipher":"aes","iter":100000,"iv":"Ib19BVMCP3VqoeQ+","salt":"9DRsMkbtRvo="},"data_key":"eyJ2IjoxLCJhZGF0YSI6IiIsImtzIjoyNTYsImN0IjoieDcrdklNazBCYThnbWlMMGZ3WHE0TGpMVkNUYVBjaFhZWDFSUUkrL2oraGlBR2V0b3BxS0w2ZG5CbUU9IiwidHMiOjk2LCJtb2RlIjoiZ2NtIiwiY2lwaGVyIjoiYWVzIiwiaXRlciI6MTAwMDAwLCJpdiI6IkgzTXlEcXB4SXUrMGNoVTgiLCJzYWx0IjoiN0RSYzZmWkZWcFE9In0="}
84
+ A={"ciphertext":{"v":1,"adata":"","ks":256,"ct":"6Hqk69PLuImnpTWSjw==","ts":96,"mode":"gcm","cipher":"aes","iter":100000,"iv":"oy5lea/k99nsZz8/","salt":"yYrMK6MbXfQ="},"data_key":"eyJ2IjoxLCJhZGF0YSI6IiIsImtzIjoyNTYsImN0IjoiN3gySUZIZmk2NjB6VnpqWDd4MjJqTUlHeXdZclRuY3E1cGdOcHU1RTB2R2I3MWMvbVp3ZjR0cUxtSk09IiwidHMiOjk2LCJtb2RlIjoiZ2NtIiwiY2lwaGVyIjoiYWVzIiwiaXRlciI6MTAwMDAwLCJpdiI6IkJ1a1lBRGJhaHVvcDJuM2YiLCJzYWx0IjoiKzhVOWhiaUtCRmc9In0="}
85
+ ENV={"ciphertext":{"v":1,"adata":"","ks":256,"ct":"FQfnNaMl936fhZo3Ykrx","ts":96,"mode":"gcm","cipher":"aes","iter":100000,"iv":"12QqZqCxkvMbagzo","salt":"A3YypAcXUIQ="},"data_key":"eyJ2IjoxLCJhZGF0YSI6IiIsImtzIjoyNTYsImN0IjoiL2xpM0NnaG5BUmJCM3NmMlA5aTNLRXd3eFBITk9HQVFTdFBzVHFWUXRIZGRBRHNOL0wzV1Jrc3dIbGM9IiwidHMiOjk2LCJtb2RlIjoiZ2NtIiwiY2lwaGVyIjoiYWVzIiwiaXRlciI6MTAwMDAwLCJpdiI6ImFEK1dIZEwwWnlzbmJ5d0QiLCJzYWx0IjoiZ3hlL3dYVU9GRmM9In0="}
86
+ K={"ciphertext":{"v":1,"adata":"","ks":256,"ct":"wpSRhDud1zqxhlvqdQ==","ts":96,"mode":"gcm","cipher":"aes","iter":100000,"iv":"9WnyuuOx2q6J/KCR","salt":"kZNxqsQE8o0="},"data_key":"eyJ2IjoxLCJhZGF0YSI6IiIsImtzIjoyNTYsImN0IjoiWHpsSWEzZEVoeWNHQ0lDQTJvU2xZem93SFZUeU1CVGUyb1dwNkVZcm9JamR4azg4SnVXci9USlIxaUE9IiwidHMiOjk2LCJtb2RlIjoiZ2NtIiwiY2lwaGVyIjoiYWVzIiwiaXRlciI6MTAwMDAwLCJpdiI6IkUxdGNNT0E0YkpBSzlEdGMiLCJzYWx0IjoibzRZcjQ5U3NhVU09In0="}
87
+
88
+ # --env-formatted plays nicely with pipes too
89
+ hydan encrypt --env-formatted --master-key $KEY < test.env | hydan decrypt --env-formatted --master-key $KEY
90
+ FOO=bar
91
+ BAR=baz
92
+ BAZ=bat
93
+ A=B
94
+ ENV=ENV
95
+ K=V
96
+
97
+ # This can easily be used to construct export statements to be evaluated via eval
98
+ hydan encrypt --env-formatted --master-key $KEY < test.env | hydan decrypt --env-formatted --master-key $KEY | awk '{ print "export " $1 }'
99
+ export FOO=bar
100
+ export BAR=baz
101
+ export BAZ=bat
102
+ export A=B
103
+ export ENV=ENV
104
+ export K=V
105
+ ```
106
+
107
+ #### Large files
108
+ When files are too large to read into memory, use the `--in` and `--out` flags. This will prompt `hydan` to use logic that reads and encrypts the file line-by-line, as opposed to "slurping" the file beforehand. This also implies that it's not worth Base64 encoding the encrypted output, since it will also be large. Because of this, encryption that uses the `--in` flag saves it's output in binary instead of Base64.
109
+
110
+ ```
111
+ # Make a huge file
112
+ mkfile -n 10g ~/Desktop/LargeTestFile
113
+
114
+ hydan encrypt --in ~/Desktop/LargeTestFile --out ~/Desktop/LargeTestFile.bin --master-key $KEY
115
+ Data key (Base64): U2FsdGVkX18NG/y8sEFGyop79njj0R9omH+/UZ3Ijy1c8nYACE2UQt1NMvSL2Rh9GH4p+TSEZxSMqqWqzg7/Kw==
116
+
117
+ # We use the encrypted data key generated by the program in order to decrypt the file
118
+ # If `--key-out` is specified, the key will be saved to the supplied path instead of
119
+ # being printed to STDOUT.
120
+ hydan decrypt --in ~/Desktop/LargeTestFile.bin --out ~/Desktop/LargeTestFile.decrypted --master-key $KEY --data-key U2FsdGVkX18NG/y8sEFGyop79njj0R9omH+/UZ3Ijy1c8nYACE2UQt1NMvSL2Rh9GH4p+TSEZxSMqqWqzg7/Kw==
121
+
122
+ # Original
123
+ shasum -a 256 ~/Desktop/LargeTestFile
124
+ 732377e7f4a2abdc13ddfa1eb4c9c497fd2a2b294674d056cf51581b47dd586d /Users/roberto/Desktop/LargeTestFile
125
+
126
+ # Decrypted
127
+ shasum -a 256 ~/Desktop/LargeTestFile.decrypted
128
+ 732377e7f4a2abdc13ddfa1eb4c9c497fd2a2b294674d056cf51581b47dd586d /Users/roberto/Desktop/LargeTestFile.decrypted
129
+ ```
130
+
131
+ ## Development
132
+
133
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
134
+
135
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
136
+
137
+ ## Contributing
138
+
139
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hydan.
140
+
141
+
142
+ ## License
143
+
144
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
145
+
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ Rake::TestTask.new(:ci_test) do |t|
11
+ t.libs << "test"
12
+ t.libs << "lib"
13
+ t.test_files = FileList['test/**/*ci_test.rb']
14
+ end
15
+
16
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "hydan"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/hydan ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "hydan"
4
+
5
+ Hydan::CLI.start(ARGV)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/circle.yml ADDED
@@ -0,0 +1,29 @@
1
+ machine:
2
+ environment:
3
+ TARGETS: '2.1 2.2 2.3'
4
+ services:
5
+ - docker
6
+
7
+ dependencies:
8
+ override:
9
+ - gem install rubocop
10
+ - | # Build required images
11
+ for v in ${TARGETS[*]}; do
12
+ echo "Building version $v..."
13
+ sed "s/#VERSION#/$v/g" Dockerfile.tpl > Dockerfile
14
+ docker build -t $REGISTRY_URL/seibelsbi/docker-hydan:$v .
15
+ done
16
+
17
+ test:
18
+ override:
19
+ - docker run -it --entrypoint bash $REGISTRY_URL/seibelsbi/docker-hydan:2.1 -c 'rake ci_test'
20
+ - docker run -it --entrypoint bash $REGISTRY_URL/seibelsbi/docker-hydan:2.2 -c 'rake ci_test'
21
+ - docker run -it --entrypoint bash $REGISTRY_URL/seibelsbi/docker-hydan:2.3 -c 'rake ci_test'
22
+
23
+ deployment:
24
+ master:
25
+ branch: master
26
+ commands:
27
+ - docker login -e=$REGISTRY_EMAIL -u=$REGISTRY_USER -p=$REGISTRY_PASSWORD $REGISTRY_URL
28
+ - docker tag $REGISTRY_URL/seibelsbi/docker-hydan:2.3 $REGISTRY_URL/seibelsbi/docker-hydan:latest
29
+ - docker push $REGISTRY_URL/seibelsbi/docker-hydan:latest
data/hydan.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hydan/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hydan"
8
+ spec.version = Hydan::VERSION
9
+ spec.authors = ["Roberto Acevedo"]
10
+ spec.email = ["rxacevedo@fastmail.com"]
11
+
12
+ spec.summary = %q{A Ruby gem for KMS and local envelope encryption.}
13
+ spec.description = %q{Hide your secrets.}
14
+ spec.homepage = "https://github.com/seibelsbi/hydan"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "bin"
27
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.11"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "minitest", "~> 5.0"
33
+ spec.add_development_dependency "pry", "~> 0.10"
34
+ spec.add_development_dependency "pry-doc", ">= 0.6.0"
35
+ spec.add_development_dependency "yard"
36
+
37
+ spec.add_dependency "thor"
38
+ spec.add_dependency "aws-sdk", "~> 2"
39
+ spec.add_dependency "gibberish"
40
+ end
data/lib/hydan/cli.rb ADDED
@@ -0,0 +1,130 @@
1
+ module Hydan
2
+ class CLIBase < Thor
3
+ def self.shared_options
4
+ method_option(
5
+ :master_key,
6
+ :type => :string,
7
+ :desc => 'The symmetric master key used to encrypt the exported data key',
8
+ :required => true
9
+ )
10
+ end
11
+ def self.shared_text_options
12
+ method_option(
13
+ :env_formatted,
14
+ :type => :boolean,
15
+ :desc => 'Indicates that the input is .env formatted (K=V). Results in K=encrypt(V) output.'
16
+ )
17
+ method_option(
18
+ :text,
19
+ :type => :array,
20
+ :desc => 'The plaintext to be encrypted'
21
+ )
22
+ end
23
+ def self.shared_file_options
24
+ method_option(
25
+ :in,
26
+ :type => :string,
27
+ :desc => 'The file being encrypted'
28
+ )
29
+ method_option(
30
+ :out,
31
+ :type => :string,
32
+ :desc => 'Where the encrypted content should be written'
33
+ )
34
+ end
35
+ end
36
+
37
+ class CLI < CLIBase
38
+
39
+ include Hydan::IO
40
+ LOGGER = Logger.new(STDOUT)
41
+ LOGGER.level = Logger::INFO
42
+
43
+ desc 'encrypt', 'Encrypt a string or file'
44
+ shared_options
45
+ shared_text_options
46
+ # This is only here to support branching over to encrypt-file
47
+ method_option(
48
+ :in,
49
+ :type => :string,
50
+ :desc => 'The file being encrypted'
51
+ )
52
+ def encrypt(*args)
53
+ if options[:in]
54
+ invoke :encrypt_file
55
+ else
56
+ master_key = Base64.strict_decode64(options[:master_key])
57
+ client = Hydan::Crypto::EncryptionHelper.new(master_key)
58
+ data = handle_input(options)
59
+ json = client.encrypt(data) unless options[:env_formatted]
60
+ json = client.encrypt_env_formatted(data) if options[:env_formatted]
61
+ handle_output(json)
62
+ end
63
+ end
64
+
65
+ desc 'encrypt-file', 'Encrypt a file'
66
+ shared_options
67
+ shared_file_options
68
+ # Only used for file encryption
69
+ method_option(
70
+ :key_out,
71
+ :type => :string,
72
+ :desc => 'Where the encrypted data key should be written'
73
+ )
74
+ def encrypt_file(*args)
75
+ master_key = Base64.strict_decode64(options[:master_key])
76
+ client = Hydan::Crypto::EncryptionHelper.new(master_key)
77
+ encrypted_data_key_blob = client.encrypt_file(
78
+ options[:in],
79
+ options[:out]
80
+ )
81
+ handle_key_output(encrypted_data_key_blob, options[:key_out])
82
+ end
83
+
84
+ desc 'decrypt', 'Decrypt a string or file'
85
+ shared_options
86
+ shared_text_options
87
+ # This is only here to support branching over to encrypt-file
88
+ method_option(
89
+ :in,
90
+ :type => :string,
91
+ :desc => 'The file being encrypted'
92
+ )
93
+ def decrypt(*args)
94
+ if options[:in]
95
+ invoke :decrypt_file
96
+ else
97
+ key = Base64.strict_decode64(options[:master_key])
98
+ client = Hydan::Crypto::DecryptionHelper.new(key)
99
+ data = handle_input(options)
100
+ plaintext = client.decrypt(data) unless options[:env_formatted]
101
+ plaintext = client.decrypt_env_file(data) if options[:env_formatted]
102
+ handle_output(plaintext)
103
+ end
104
+ end
105
+
106
+ desc 'decrypt-file', 'Decrypt a file'
107
+ shared_options
108
+ shared_file_options
109
+ method_option(
110
+ :data_key,
111
+ :type => :string,
112
+ :desc => 'The data key used to decrypt encypted data',
113
+ :required => true
114
+ )
115
+ def decrypt_file(*args)
116
+ master_key = Base64.strict_decode64(options[:master_key])
117
+ data_key = Base64.strict_decode64(options[:data_key])
118
+ # TODO: Clear keys
119
+ client = Hydan::Crypto::DecryptionHelper.new(master_key)
120
+ client.decrypt_file(options[:in], options[:out], data_key)
121
+ end
122
+
123
+ desc 's3', 'Use the S3 API'
124
+ subcommand 's3', Hydan::S3::S3Cmd
125
+
126
+ desc 'kms', 'Use the KMS API for encryption/decryption'
127
+ subcommand 'kms', Hydan::Crypto::KMS::KMSCmd
128
+
129
+ end
130
+ end
@@ -0,0 +1,51 @@
1
+ module Hydan
2
+ module Crypto
3
+ class DecryptionHelper
4
+
5
+ def initialize(symmetric_key)
6
+ @master_key = symmetric_key
7
+ @generator = OpenSSL::Cipher.new(Crypto::DEFAULT_CIPHER)
8
+ end
9
+
10
+ # Decrypts a JSON object
11
+ # @return [String]
12
+ def decrypt(json)
13
+ input_hash = JSON.parse(json)
14
+ data_key = Base64.strict_decode64(input_hash['data_key'])
15
+ key_cipher = Gibberish::AES.new(@master_key)
16
+ plaintext_key = key_cipher.decrypt(data_key)
17
+ data_cipher = Gibberish::AES.new(plaintext_key)
18
+ plaintext = data_cipher.decrypt(JSON.generate(input_hash['ciphertext']))
19
+ plaintext
20
+ end
21
+
22
+ # Decrypts a file
23
+ def decrypt_file(in_file, out_file, key)
24
+ key_cipher = Gibberish::AES::CBC.new(@master_key)
25
+ # The return value for this is Base64-encoded by default,
26
+ # we're overriding it here to later #strict_encode64 it.
27
+ data_key = key_cipher.decrypt(key, binary: true)
28
+ data_cipher = Gibberish::AES::CBC.new(data_key)
29
+ data_key = nil # Scrub from memory as soon as feasible
30
+ data_cipher.decrypt_file(in_file, out_file)
31
+ end
32
+
33
+ # # Decrypts an env-formatted text string.
34
+ # # A file is considered to be env-formatted when:
35
+ # # - Each line consists of K=V pairs
36
+ # # - Each V is a JSON string that contains a Gibberish
37
+ # # payload (ciphertext, IV, salt, etc) and an encrypted
38
+ # # data key that was used to encrypt the ciphertext
39
+ # # @return [String]
40
+ def decrypt_env_file(env_body)
41
+ new_text = []
42
+ env_body.each_line do |l|
43
+ k, v = l.match(Hydan::IO::ENV_LINE_REGEX).captures
44
+ dec_v = decrypt(v)
45
+ new_text << "#{k}=#{dec_v}"
46
+ end
47
+ new_text
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,56 @@
1
+ # Class to simplify envelope encryption
2
+
3
+ require 'openssl'
4
+
5
+ module Hydan
6
+ module Crypto
7
+ class EncryptionHelper
8
+
9
+ def initialize(master_key)
10
+ @master_key = master_key
11
+ @generator = OpenSSL::Cipher.new(Crypto::DEFAULT_CIPHER)
12
+ @generator.encrypt
13
+ end
14
+
15
+ # Returns a JSON string containing the ciphertext (Base64 encoded)
16
+ # and the encrypted data key used to encrypt it
17
+ def encrypt(plaintext)
18
+ data_key = @generator.random_key
19
+ key_cipher = Gibberish::AES.new(@master_key)
20
+ data_cipher = Gibberish::AES.new(data_key)
21
+ output = {
22
+ 'ciphertext' => JSON.parse(data_cipher.encrypt(plaintext)),
23
+ 'data_key' => Base64.strict_encode64(key_cipher.encrypt(data_key))
24
+ }
25
+ JSON.pretty_generate output
26
+ end
27
+
28
+ # Encrypts a file and returns the encrypted data key
29
+ # that was generated for the file. File encryption
30
+ # uses a different library method that is basically
31
+ # line-by-line read-encrypt-write mechanism.
32
+ def encrypt_file(in_file, out_file)
33
+ data_key = @generator.random_key
34
+ key_cipher = Gibberish::AES::CBC.new(@master_key)
35
+ data_cipher = Gibberish::AES::CBC.new(data_key)
36
+ # The return value for this is Base64-encoded by default,
37
+ # we're overriding it here to later #strict_encode64 it.
38
+ encrypted_data_key = key_cipher.encrypt(data_key, binary: true)
39
+ data_key = nil # Scrub from memory as soon as feasible
40
+ data_cipher.encrypt_file(in_file, out_file)
41
+ encrypted_data_key
42
+ end
43
+ # TODO: This may be better suited for the plaintext
44
+ # encryption entrypoint (STDIN or --plaintext flag)
45
+ def encrypt_env_formatted(plaintext)
46
+ new_text = []
47
+ plaintext.each_line do |l|
48
+ k, v = l.match(Hydan::IO::ENV_LINE_REGEX).captures
49
+ enc_v = JSON.generate(JSON.parse(encrypt(v)))
50
+ new_text << "#{k}=#{enc_v}"
51
+ end
52
+ new_text
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,45 @@
1
+ # Class to simplify KMS decryption interface
2
+
3
+ module Hydan
4
+ module Crypto
5
+ module KMS
6
+ class DecryptionHelper
7
+
8
+ include Hydan::Crypto
9
+
10
+ def initialize
11
+ @kms = Aws::KMS::Client.new
12
+ end
13
+
14
+ # Decrypts a JSON object
15
+ # @return [String]
16
+ def decrypt(json)
17
+ input_hash = JSON.parse(json)
18
+ data_key = Base64.strict_decode64(input_hash['data_key'])
19
+ plaintext_key = @kms.decrypt(:ciphertext_blob => data_key).plaintext
20
+ cipher = Gibberish::AES.new(plaintext_key)
21
+ plaintext = cipher.decrypt(JSON.generate(input_hash['ciphertext']))
22
+ plaintext
23
+ end
24
+
25
+ # Decrypts an env-formatted text string.
26
+ # A file is considered to be env-formatted when:
27
+ # - Each line consists of K=V pairs
28
+ # - Each V is a JSON string that contains a Gibberish
29
+ # payload (ciphertext, IV, salt, etc) and an encrypted
30
+ # data key that was used to encrypt the ciphertext
31
+ # @return [String]
32
+ def decrypt_env_file(env_body)
33
+ new_text = []
34
+ env_body.each_line do |l|
35
+ k, v = l.match(Hydan::IO::ENV_LINE_REGEX).captures
36
+ dec_v = decrypt(v)
37
+ new_text << "#{k}=#{dec_v}"
38
+ end
39
+ new_text
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,56 @@
1
+ # Class to simplify KMS encryption interface
2
+
3
+ module Hydan
4
+ module Crypto
5
+ module KMS
6
+ class EncryptionHelper
7
+
8
+ include Hydan::Crypto
9
+
10
+ # Initializes the EncryptionHelper object with an
11
+ # Aws::KMS::Client.
12
+ def initialize
13
+ @kms = Aws::KMS::Client.new
14
+ end
15
+
16
+ # TODO: Should this be private?
17
+ # Returns the KMS key ID for a given alias
18
+ def get_kms_key_id(kms_key_alias)
19
+ unless @kms.nil?
20
+ aliases = @kms.list_aliases.aliases
21
+ kms_key = aliases.find { |a| a.alias_name == kms_key_alias }
22
+ kms_key_id = kms_key.target_key_id
23
+ kms_key_id
24
+ end
25
+ end
26
+
27
+ # Returns a JSON string containing the ciphertext (Base64 encoded)
28
+ # and the encrypted data key used to encrypt it
29
+ def encrypt(plaintext, kms_key_id, &block)
30
+ unwrapped = block.call(plaintext) if block
31
+ resp = @kms.generate_data_key(
32
+ key_id: kms_key_id,
33
+ key_spec: 'AES_256'
34
+ )
35
+ cipher = Gibberish::AES.new(resp[:plaintext])
36
+ output = {
37
+ 'ciphertext' => JSON.parse(cipher.encrypt(unwrapped || plaintext)),
38
+ 'data_key' => Base64.strict_encode64(resp[:ciphertext_blob])
39
+ }
40
+ JSON.pretty_generate output
41
+ end
42
+
43
+ def encrypt_env_file(plaintext, kms_key_id)
44
+ new_text = []
45
+ plaintext.each_line do |l|
46
+ k, v = l.match(Hydan::IO::ENV_LINE_REGEX).captures
47
+ enc_v = JSON.generate(JSON.parse(encrypt(v, kms_key_id)))
48
+ new_text << "#{k}=#{enc_v}"
49
+ end
50
+ new_text
51
+ end
52
+
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ module Hydan
2
+ module Crypto
3
+ module KMS
4
+ # I think there are some path resolution issues going on here
5
+ require 'hydan/io'
6
+ class KMSCmd < Thor
7
+
8
+ include Hydan::IO
9
+ desc 'encrypt', 'Encrypt a string or file'
10
+ method_option :env_formatted, :type => :boolean
11
+ method_option :file, :type => :string
12
+ method_option :key_alias, :type => :string, :required => true
13
+ method_option :out, :type => :string
14
+ method_option :text, :type => :array
15
+ def encrypt(*args)
16
+ client = Hydan::Crypto::KMS::EncryptionHelper.new
17
+ kms_key_id = client.get_kms_key_id options[:key_alias]
18
+
19
+ # TODO: Implement encrypt-file here, same as local enc/dec
20
+ if options[:file]
21
+ file = File.open(options[:file], 'r')
22
+ json = client.encrypt(file, kms_key_id) { |f, k| f.read } unless options[:env_formatted]
23
+ json = client.encrypt_env_file(file, kms_key_id) { |f, k| f.read } if options[:env_formatted]
24
+ handle_output(json)
25
+ else
26
+ text = handle_input(options)
27
+ json = client.encrypt(text, kms_key_id) unless options[:env_formatted]
28
+ json = client.encrypt_env_file(text, kms_key_id) if options[:env_formatted]
29
+ handle_output(json)
30
+ end
31
+ end
32
+
33
+ desc 'decrypt', 'Decrypts a string or file'
34
+ method_option :file, :type => :string
35
+ method_option :env_formatted, :type => :boolean
36
+ method_option :out, :type => :string
37
+ def decrypt(*args)
38
+
39
+ client = Hydan::Crypto::KMS::DecryptionHelper.new
40
+
41
+ if options[:file]
42
+ file = File.open(options[:file], 'r')
43
+ plaintext = client.decrypt(file.read) unless options[:env_formatted]
44
+ plaintext = client.decrypt_env_file(file.read) if options[:env_formatted]
45
+ handle_output(plaintext)
46
+ else
47
+ data = handle_input(options)
48
+ plaintext = client.decrypt(data) unless options[:env_formatted]
49
+ plaintext = client.decrypt_env_file(data) if options[:env_formatted]
50
+ handle_output(plaintext)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ module Hydan
2
+ module Crypto
3
+ DEFAULT_CIPHER = 'AES-256-CBC'
4
+ end
5
+ end
data/lib/hydan/io.rb ADDED
@@ -0,0 +1,41 @@
1
+ module Hydan
2
+ module IO
3
+ ENV_LINE_REGEX = /(.*?)=(.*)/
4
+
5
+ # Reads text from STDIN, or uses the value supplied with
6
+ # --plaintext, if any. Returns the text.
7
+ # @return [String]
8
+ def handle_input(options)
9
+ text = options[:text].join ' ' if options[:text]
10
+ unless options[:text]
11
+ text = ''
12
+ text << $LAST_READ_LINE while $stdin.gets # unless $stdin.tty?
13
+ end
14
+ # raise ArgumentError.new('No plaintext specified') if text.empty?
15
+ text
16
+ end
17
+
18
+ # Output phase of the encryption process, prints output
19
+ # to STDOUT or uses the value supplied with --out to write
20
+ # output to a file, if any.
21
+ # @return [Nil]
22
+ def handle_output(json)
23
+ File.open(options[:out], 'w') { |f| f.write json } if options[:out]
24
+ puts json unless options[:out]
25
+ nil
26
+ end
27
+
28
+ # Handles the output phase for file encryption/decryption.
29
+ # This only concerns the encrypted data key, since file
30
+ # encryption automatically assumes that an output file is being
31
+ # used (by the library). The input encrypted_data_key is expected
32
+ # to be a binary key, *not* Base64 encoded.
33
+ def handle_key_output(encrypted_data_key_blob, out_key_file = nil)
34
+ File.open(out_key_file, 'wb') {
35
+ |f| f.write encrypted_data_key_blob
36
+ } if out_key_file
37
+ puts "Data key (Base64): #{Base64.strict_encode64(encrypted_data_key_blob)}" unless out_key_file
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ module Hydan
2
+ module PathTypes
3
+ S3 = :s3
4
+ # S3_Folder = :s3_folder
5
+ # S3_Object = :s3_object
6
+ UNIX = :unix
7
+ end
8
+ end
data/lib/hydan/s3.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'thor'
2
+
3
+ module Hydan
4
+ module S3
5
+ # S3 command class
6
+ class S3Cmd < Thor
7
+ # TODO: This still doesn't account for the S3EncryptedClient's upload/download functions, which read/write binary
8
+ # encoded files (not the JSON/base64 stuff that I'm doing here).
9
+ desc 'cp', 'Use the S3 API to copy files'
10
+ method_option :decrypt, :type => :boolean
11
+ method_option :key_alias, :type => :string
12
+ # Copies src to dest (args[0] and args[1]). Handles S3->local (download)
13
+ # and local->S3 (upload).
14
+ def cp (*args)
15
+ src, dest = args.take 2
16
+ src_type, dest_type = [S3Helper.parse_path(src), S3Helper.parse_path(dest)]
17
+
18
+ event = if src_type == PathTypes::UNIX && dest_type == PathTypes::S3
19
+ :upload
20
+ elsif src_type == PathTypes::S3 && dest_type == PathTypes::UNIX
21
+ :download
22
+ else
23
+ :invalid
24
+ end
25
+
26
+ if event == :upload
27
+ bucket, key = S3Helper.parse_s3_path dest
28
+ kms_client = Hydan::Crypto::KMS::EncryptionHelper.new
29
+ kms_key_id = kms_client.get_kms_key_id(options[:key_alias]) if options[:key_alias]
30
+ client = S3Helper.new(kms_key_id)
31
+ client.upload(bucket, key, File.open(src, 'r').read)
32
+ elsif event == :download
33
+ bucket, key = S3Helper.parse_s3_path src
34
+ client = S3Helper.new(options[:decrypt])
35
+ client.download(bucket, key, dest)
36
+ else puts "Invalid"
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ # Wrapper class surrounding common S3 functions
44
+ class S3Helper
45
+ S3_PATH_REGEX = %r{s3:\/\/(.*?)\/(.*)}
46
+
47
+ # Initialize the S3Helper object. When a kms_key_id is given, the
48
+ # client uses an Aws::S3::Encrpytion::Client. If omitted, a regular
49
+ # Aws::S3::Client is used instead.
50
+ def initialize(kms_key_id = nil)
51
+ @s3 = Aws::S3::Client.new unless kms_key_id
52
+ @s3 = Aws::S3::Encryption::Client.new(
53
+ kms_key_id: kms_key_id
54
+ ) if kms_key_id
55
+ end
56
+
57
+ # Performs a PutObject operation for content at s3://bucket/key
58
+ def upload(bucket, key, body)
59
+ @s3.put_object(
60
+ bucket: bucket,
61
+ key: key,
62
+ body: body
63
+ )
64
+ end
65
+
66
+ # Downloads the object located at s3://bucket/prefix and writes
67
+ # the content to dest
68
+ def download(bucket, prefix, dest = nil)
69
+ resp = @s3.get_object(bucket: bucket, key: prefix)
70
+ content = resp.body.string
71
+ File.open(dest, 'w') { |f| f.write content } if dest
72
+ puts content unless dest
73
+ end
74
+
75
+ # Parses a given string path and returns the type
76
+ # (constants in Hydan::PathTypes)
77
+ def self.parse_path(path)
78
+ # If we "parse" it as an S3 path, we'll let the S3 client throw
79
+ # an error if it's a non-existant path
80
+ return PathTypes::S3 if path.start_with? 's3://'
81
+ return PathTypes::UNIX unless path.start_with? 's3://'
82
+ end
83
+
84
+ # Parses an S3 path and returns regex capture
85
+ # groups [bucket, key]
86
+ def self.parse_s3_path(s3_path)
87
+ s3_path.match(S3_PATH_REGEX).captures
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module Hydan
2
+ VERSION = '0.1.1'.freeze
3
+ end
data/lib/hydan.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'aws-sdk'
2
+ require 'base64'
3
+ require 'English'
4
+ require 'gibberish'
5
+ require 'logger'
6
+ require 'thor'
7
+ require 'hydan/crypto/kms'
8
+ require 'hydan/crypto/kms/encrypt'
9
+ require 'hydan/crypto/kms/decrypt'
10
+ require 'hydan/path_types'
11
+ require 'hydan/io'
12
+ require 'hydan/crypto'
13
+ require 'hydan/crypto/encrypt'
14
+ require 'hydan/crypto/decrypt'
15
+ require 'hydan/s3'
16
+ require 'hydan/cli'
17
+ require 'hydan/version'
18
+
19
+ module Hydan end
metadata ADDED
@@ -0,0 +1,199 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hydan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Roberto Acevedo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-doc
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.6.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.6.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: thor
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: aws-sdk
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2'
125
+ - !ruby/object:Gem::Dependency
126
+ name: gibberish
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Hide your secrets.
140
+ email:
141
+ - rxacevedo@fastmail.com
142
+ executables:
143
+ - console
144
+ - hydan
145
+ - setup
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - ".gitignore"
150
+ - ".pre-commit-config.yaml"
151
+ - Dockerfile.tpl
152
+ - Gemfile
153
+ - Gemfile.lock
154
+ - README.md
155
+ - Rakefile
156
+ - bin/console
157
+ - bin/hydan
158
+ - bin/setup
159
+ - circle.yml
160
+ - hydan.gemspec
161
+ - lib/hydan.rb
162
+ - lib/hydan/cli.rb
163
+ - lib/hydan/crypto.rb
164
+ - lib/hydan/crypto/decrypt.rb
165
+ - lib/hydan/crypto/encrypt.rb
166
+ - lib/hydan/crypto/kms.rb
167
+ - lib/hydan/crypto/kms/decrypt.rb
168
+ - lib/hydan/crypto/kms/encrypt.rb
169
+ - lib/hydan/io.rb
170
+ - lib/hydan/path_types.rb
171
+ - lib/hydan/s3.rb
172
+ - lib/hydan/version.rb
173
+ homepage: https://github.com/seibelsbi/hydan
174
+ licenses:
175
+ - MIT
176
+ metadata:
177
+ allowed_push_host: https://rubygems.org
178
+ post_install_message:
179
+ rdoc_options: []
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubyforge_project:
194
+ rubygems_version: 2.4.8
195
+ signing_key:
196
+ specification_version: 4
197
+ summary: A Ruby gem for KMS and local envelope encryption.
198
+ test_files: []
199
+ has_rdoc: