envcrypt 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7670f789a389fdc05ec8478eeb4072aea8de5b01
4
- data.tar.gz: cbd4f2c8a1c0a10f7b3be10bc7f9a9f9efa1faee
3
+ metadata.gz: 04c0530b0a65f7f72d719fd7c6caf06935b13fef
4
+ data.tar.gz: e9f9b03c19787d5079c1309c72fc45afd9d16509
5
5
  SHA512:
6
- metadata.gz: 9a09fd0621123f10b47f68103b0ab5a2b7fba8700a8f3ebda98f549d893dc092946da69f8a9f6b579ad9c0d52f93764be333b6229ad96ac4f73a8f8acc88f548
7
- data.tar.gz: 5f86edbfb5f91ed7fea2eadb629761e048e705c198357d23676190c85023efa2fb7120a78ef972543034b42007365885dd2e24fd2e941d58d5fe4863f4da04e9
6
+ metadata.gz: ff8940058084df79cd6b99aaf77db8d4031269b7bce2d7d2694744f4990a8c3a29008f11f74e91cceff693df2825fa6cad45e23a50a2168201b48fdee5e4fd1a
7
+ data.tar.gz: 3105d2ad9e7483e506a3091a65e89a820f70cdcc1624cfc2b949b909a6369bd1e28903d44fa0dbb2edc5bcbbd1077af9537ad91814f12a028de02c863976c007
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: '1'
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *~
2
+ /vendor
3
+ /.yardoc
4
+ /doc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p353
data/Gemfile CHANGED
@@ -1,2 +1,9 @@
1
+ # -*- mode: ruby -*-
1
2
  source 'https://rubygems.org'
2
3
  ruby '2.0.0'
4
+
5
+ group :development do
6
+ gem 'rspec', '~> 2.14'
7
+ gem 'yard'
8
+ gem 'yard-tomdoc'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,25 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.2.5)
5
+ rspec (2.14.1)
6
+ rspec-core (~> 2.14.0)
7
+ rspec-expectations (~> 2.14.0)
8
+ rspec-mocks (~> 2.14.0)
9
+ rspec-core (2.14.8)
10
+ rspec-expectations (2.14.5)
11
+ diff-lcs (>= 1.1.3, < 2.0)
12
+ rspec-mocks (2.14.6)
13
+ tomparse (0.4.2)
14
+ yard (0.8.7.4)
15
+ yard-tomdoc (0.7.1)
16
+ tomparse (>= 0.4.0)
17
+ yard
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ rspec (~> 2.14)
24
+ yard
25
+ yard-tomdoc
data/README.md CHANGED
@@ -1,50 +1,53 @@
1
1
  Envcrypt
2
2
  =========
3
3
 
4
- Encryptor provides an easy way to securely encrypt and decrypt secrets
4
+ Envcrypt provides an easy way to securely encrypt and decrypt secrets
5
5
  (passwords) that need to be stored for use in automated processes.
6
6
 
7
7
  **Status:** Just have a README! Working on the rest.
8
8
 
9
9
  ## Use
10
10
 
11
- Encrypt a secret
12
- ````ruby
13
- $ envcrypt -p mypassword
11
+ Encrypt a secret via
14
12
 
15
- encrypted: xxx
16
- key: xxx
13
+ ````ruby
14
+ $ envcrypt -s Orange
15
+ Encrypted Secret: zTbH59gpFIIuXGYRuK9pHQ==
16
+ ENVCRYPT_KEY='eWa7QqyF6eE/bEthGO4BgA==$9OZzJ6xIgEcovfEOHIhVb9Gaw5/FeSgDmTErws1+API=$ccRiLqJjyL6MypWHOGfpcQ=='
17
+ WARNING: It is critical that the key and encryption password be stored separately!
17
18
  ````
18
19
 
19
20
  Set the key as an environment variable (bash example)
21
+
20
22
  ````bash
21
- export ENVCRYPT_KEY=xxx
23
+ $ export ENVCRYPT_KEY='eWa7QqyF6eE/bEthGO4BgA==$9OZzJ6xIgEcovfEOHIhVb9Gaw5/FeSgDmTErws1+API=$ccRiLqJjyL6MypWHOGfpcQ=='
22
24
  ````
23
25
 
24
- Decrypt the password in Ruby code
26
+ Go ahead and test decryption from the command line
25
27
  ````ruby
26
- require 'envcrypt'
27
-
28
- encrypted_pwd = "xxx"
29
- decrypted_pwd = Envcrypt::decrypt(encrypted_pwd, key: ENV['ENVCRYPT_KEY'])
28
+ $ envcrypt -d 'zTbH59gpFIIuXGYRuK9pHQ=='
29
+ Decrypted: Orange
30
30
  ````
31
31
 
32
- The second argument to decrypt is **optional**. The default `key` is
33
- `ENV['ENVCRYPT_KEY']`, but you have to option to set it explicitly if you want to
34
- get it from somewhere else.
35
32
 
36
- ##### Optional
33
+ Decrypt the password in Ruby code
37
34
 
38
- **Need to be able to set a mode so we can use this with Heroku's version of OpenSSL.
39
- Not sure exactly how this will work**
35
+ ````ruby
36
+ require 'envcrypt'
37
+
38
+ encrypted_pwd = "zTbH59gpFIIuXGYRuK9pHQ=="
39
+ crypt = Envcrypter.new(key: ENV['ENVCRYPT_KEY']) #key is optional (default: ENV['ENVCRYPT_KEY'])
40
+ decrypted_pwd = crypt.decrypt(encrypted_pwd)
41
+ ````
40
42
 
41
43
  ##### Using existing keys to encrypt secrets
42
44
 
43
- Secrets can also be encrypted using existing keys if you want to use
44
- one key to encrypt multiple secrets.
45
+ By default a new encryption key is created for each use command line
46
+ `envcrypt` tool. Secrets can also be encrypted using existing keys if
47
+ you want to use one key to encrypt multiple secrets.
45
48
 
46
49
  ````ruby
47
- $ envcrypt -p mypassword -k xxx
50
+ $ envcrypt -p Orange -k $ENVCRYPT_KEY
48
51
  ````
49
52
 
50
53
 
@@ -56,10 +59,9 @@ automate an interface with the web API. If an attacker somehow gains
56
59
  access to the database or file, I'm screwed if I store the password as
57
60
  plaintext or use some simple obfuscation. Envcrypt allows me to store
58
61
  an encrypted version of the password and decrypt it only when needed.
59
- The trick is to access the decryption key from an environment
60
- variable. These can be set from the command line before launching the
61
- automated process, in a locked down .bashrc file, or as Heroku config
62
- variables.
62
+ The trick is to store the decryption key in an environment variable.
63
+ These can be set from the command line before launching the automated
64
+ process, in a locked down .bashrc file, or as Heroku config variables.
63
65
 
64
66
  Of course, if an attacker was able to get a hold of *both* the password
65
67
  and the decryption keys, you're screwed, but security is all about making
data/bin/envcrypt ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "envcrypt"
4
+ require "optparse"
5
+
6
+ module EnvcryptCL
7
+ extend self
8
+
9
+ def run
10
+ set_options
11
+
12
+ if @options[:pwd]
13
+ ENV['ENVCRYPT_KEY'] = @options[:key]
14
+ crypt = Envcrypt::Envcrypter.new
15
+ encrypted = crypt.encrypt(@options[:pwd])
16
+
17
+ puts "Encrypted Secret: #{encrypted}"
18
+ puts "ENVCRYPT_KEY=\'#{crypt.key}\'"
19
+ puts "WARNING: It is critical that the key and encryption password be stored separately!"
20
+ end
21
+
22
+ if @options[:encrypted_pwd]
23
+ crypt = Envcrypt::Envcrypter.new
24
+ decrypted = crypt.decrypt(@options[:encrypted_pwd])
25
+
26
+ puts "Decrypted: #{decrypted}"
27
+ end
28
+ end
29
+
30
+
31
+ def set_options
32
+ @options = {}
33
+
34
+ OptionParser.new do |opts|
35
+ opts.banner = "Usage: envcrypt -s <SECRET>"
36
+
37
+ opts.on("-h","--help", "Show this message") do
38
+ puts opts
39
+ exit
40
+ end
41
+
42
+ @options[:pwd] = nil
43
+ opts.on("-s","--secret <SECRET>","Generates an encrypted version of SECRET") do |opt|
44
+ @options[:pwd] = opt
45
+ end
46
+
47
+ @options[:encrypted_pwd] = nil
48
+ opts.on("-d","--decrypt <ENCRYPTED SECRET>","Decrypts the encrypted secret using the ENVCRYPT_KEY environment variable") do |opt|
49
+ @options[:encrypted_pwd] = opt
50
+ end
51
+
52
+ @options[:key] = nil
53
+ opts.on("-k","--key <KEY>","Uses the specified key to encrypt; e.g., -k $ENVCRYPT_KEY") do |opt|
54
+ @options[:key] = opt
55
+ end
56
+ end.parse!
57
+ end
58
+ end
59
+
60
+ EnvcryptCL.run
data/envcrypt.gemspec CHANGED
@@ -1,11 +1,11 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
- #require 'envcrypt/version'
4
+ require 'envcrypt/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "envcrypt"
8
- s.version = "0.0.0" #Birst_Command::VERSION
8
+ s.version = Envcrypt::VERSION
9
9
  s.authors = ["Sterling Paramore"]
10
10
  s.email = ["gnilrets@gmail.com"]
11
11
  s.homepage = "https://github.com/gnilrets"
@@ -0,0 +1,125 @@
1
+ # Public: Envcrypt module contains all of the methods/classes to
2
+ # perform encryption and decryption of passwords
3
+ #
4
+ # Examples
5
+ #
6
+ # mypassword = "secret"
7
+ # crypt = Envcrypter.new
8
+ # encrypted_pwd = crypt.encrypt(mypassword)
9
+ # decrypted_pwd = crypt.decrypt(encrypted_pwd)
10
+ module Envcrypt
11
+ class Envcrypter
12
+
13
+ # Public: Returns the key used to encrypt/decrypt secrets
14
+ attr_reader :key
15
+
16
+ # Public: Initialize an Envcrypter object
17
+ #
18
+ # key - A string representing the key to be used for encryption
19
+ # and decryption (default: ENV['ENVCRYPT_KEY'])
20
+ def initialize(key: ENV['ENVCRYPT_KEY'])
21
+ @key = key == nil ? generate_key : key
22
+ @de_cipher = nil
23
+ @en_cipher = nil
24
+ end
25
+
26
+ # Public: Generates a random key
27
+ #
28
+ # Returns the key
29
+ def generate_key
30
+ @key = "#{SecureRandom.base64}$#{SecureRandom.base64(32)}$#{SecureRandom.base64}"
31
+ end
32
+
33
+
34
+ # Public: Encrypts a secret
35
+ #
36
+ # secret - the secret string to be encrypted
37
+ #
38
+ # Returns the encrypted string
39
+ def encrypt(secret)
40
+ cipher = create_cipher(:encrypt)
41
+
42
+ encrypted = cipher.update secret
43
+ encrypted << cipher.final
44
+ Base64.encode64(encrypted).chomp
45
+ end
46
+
47
+ # Public: Decrypts a secret
48
+ #
49
+ # secret - the encrypted string to be decrypted
50
+ #
51
+ # Returns the plain text decrypted string
52
+ def decrypt(encrypted)
53
+ cipher = create_cipher(:decrypt)
54
+ plaintxt = cipher.update Base64.decode64(encrypted)
55
+ plaintxt << cipher.final
56
+ end
57
+
58
+
59
+
60
+ private
61
+
62
+ # Internal: Parses a key string into three components used by the
63
+ # encryption ciphers. The components are stored as private
64
+ # instance variables. Keeping it all in a single string
65
+ # simplifies storing the key in environment variables.
66
+ #
67
+ # key - the key to be parsed
68
+ #
69
+ # Returns the key parsed into three components (iv,pwd,salt)
70
+ def parse_key(key)
71
+ parsed = key.split('$')
72
+ if parsed.length != 3
73
+ raise "Bad key format - generate a new one"
74
+ else
75
+ parsed
76
+ end
77
+ end
78
+
79
+
80
+ # Internal: Create an encryption cipher
81
+ #
82
+ # mode - Set the mode to either :encrypt or :decrypt
83
+ #
84
+ # Returns a cipher to be used for encryption or decryption
85
+ def create_cipher(mode)
86
+ create_cipher_simple(mode)
87
+ end
88
+
89
+ # Internal: Create a simple encryption cipher
90
+ #
91
+ # mode - Set the mode to either :encrypt or :decrypt
92
+ #
93
+ # Returns a cipher to be used for encryption or decryption
94
+ def create_cipher_simple(mode)
95
+ iv,pwd,salt = parse_key(@key)
96
+
97
+ cipher = OpenSSL::Cipher.new 'AES-128-CBC'
98
+ cipher.send(mode)
99
+
100
+ cipher.iv = iv
101
+ cipher.key = pwd
102
+ cipher
103
+ end
104
+
105
+
106
+ # Future: Create a cipher using the more secure pbkdf2_mac method
107
+ #
108
+ # This one is more secure but doesn't work on Heroku
109
+ # Would like to optionally detect OpenSSL version
110
+ # and use this if possible
111
+ def create_cipher_pbkdf2(mode)
112
+ iv,pwd,salt = parse_key(@key)
113
+
114
+ cipher = OpenSSL::Cipher.new 'AES-128-CBC'
115
+ cipher.send(mode)
116
+ cipher.iv = iv
117
+
118
+ digest = OpenSSL::Digest::SHA256.new
119
+ key_len = cipher.key_len
120
+ iter = 20000
121
+ cipher.key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
122
+ cipher
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,3 @@
1
+ module Envcrypt
2
+ VERSION = "0.1.0"
3
+ end
data/lib/envcrypt.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'openssl'
2
+ require 'securerandom'
3
+ require 'base64'
4
+
5
+ require 'envcrypt/envcrypt'
@@ -0,0 +1,92 @@
1
+ $LOAD_PATH << '../lib'
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+
6
+ require 'envcrypt'
7
+
8
+ include Envcrypt
9
+
10
+
11
+ describe "Envcrypt" do
12
+ describe "generating a key" do
13
+ let(:encrypter) { Envcrypter.new() }
14
+
15
+ it "should have a length of 94" do
16
+ expect(encrypter.key.length).to eq 94
17
+ end
18
+
19
+ it "should parse into 3 components delimited by $" do
20
+ expect(encrypter.key.split("$").length).to eq 3
21
+ end
22
+ end
23
+
24
+ describe "encrypting and decrypting a password" do
25
+ let(:password) { "mysecret" }
26
+
27
+ describe "with a generated key" do
28
+ it "should encrypt and decrypt properly" do
29
+ crypt = Envcrypter.new()
30
+
31
+ encrypted = crypt.encrypt(password)
32
+ plaintxt = crypt.decrypt(encrypted)
33
+
34
+ expect(plaintxt).to eq password
35
+ end
36
+ end
37
+
38
+
39
+ describe "with a supplied environment variable" do
40
+ before do
41
+ ENV['ENVCRYPT_KEY'] = "UnY9w3T5Qk3Q5JshOp/2HA==$8swxKYQxgyXaCyvMb+wP2HwqalpiSc3K4MpCvOpD2QY=$RK2cUDUHNBmI7miJcd6W4g=="
42
+ @crypt = Envcrypter.new()
43
+ end
44
+
45
+ after { ENV['ENVCRYPT_KEY'] = nil }
46
+
47
+ it "should have set the correct key" do
48
+ expect(@crypt.key).to eq ENV['ENVCRYPT_KEY']
49
+ end
50
+
51
+ it "should still encrypt and decrypt properly" do
52
+ encrypted = @crypt.encrypt(password)
53
+ plaintxt = @crypt.decrypt(encrypted)
54
+
55
+ expect(plaintxt).to eq password
56
+ end
57
+ end
58
+
59
+
60
+ describe "with a different password" do
61
+ it "should encrypt to a different string" do
62
+ crypt = Envcrypter.new()
63
+
64
+ encrypted = crypt.encrypt(password)
65
+ encrypted_different = crypt.encrypt("#{password}plus")
66
+
67
+ expect(encrypted).not_to eq encrypted_different
68
+ end
69
+ end
70
+
71
+ describe "with the same password but different key" do
72
+ before do
73
+ @crypt = Envcrypter.new()
74
+ @crypt2 = Envcrypter.new()
75
+
76
+ @encrypted = @crypt.encrypt(password)
77
+ @encrypted2 = @crypt2.encrypt(password)
78
+ end
79
+
80
+ it "should encrypt to a different string" do
81
+ expect(@encrypted).not_to eq @encrypted2
82
+ end
83
+
84
+ it "and they should still decrypt to the same password" do
85
+ plaintxt = @crypt.decrypt(@encrypted)
86
+ plaintxt2 = @crypt2.decrypt(@encrypted2)
87
+
88
+ expect(plaintxt).to eq plaintxt2
89
+ end
90
+ end
91
+ end
92
+ end
metadata CHANGED
@@ -1,26 +1,37 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: envcrypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sterling Paramore
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-30 00:00:00.000000000 Z
11
+ date: 2014-06-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Simple secure encryption/decryption of secret data (passwords)
14
14
  email:
15
15
  - gnilrets@gmail.com
16
- executables: []
16
+ executables:
17
+ - envcrypt
17
18
  extensions: []
18
19
  extra_rdoc_files: []
19
20
  files:
21
+ - .bundle/config
22
+ - .gitignore
23
+ - .rspec
24
+ - .ruby-version
20
25
  - Gemfile
26
+ - Gemfile.lock
21
27
  - LICENSE
22
28
  - README.md
29
+ - bin/envcrypt
23
30
  - envcrypt.gemspec
31
+ - lib/envcrypt.rb
32
+ - lib/envcrypt/envcrypt.rb
33
+ - lib/envcrypt/version.rb
34
+ - spec/envcrypt_spec.rb
24
35
  homepage: https://github.com/gnilrets
25
36
  licenses:
26
37
  - MIT
@@ -45,4 +56,5 @@ rubygems_version: 2.2.2
45
56
  signing_key:
46
57
  specification_version: 4
47
58
  summary: Simple secure encryption/decryption of secret data
48
- test_files: []
59
+ test_files:
60
+ - spec/envcrypt_spec.rb