master-crypt 0.0.1 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30c1cf54ea583219381fdbed0e73f77f1f4b7168fe7bf5e3a568832d50be208f
4
- data.tar.gz: 8add2b4b02dc45935f7317561b09e49a1e1bca477634a0bf3672ffaf8fc80a4c
3
+ metadata.gz: 9a11aff2304c6483147f3e7cc3d57996af1a4fd0ba730f10d3e130fec9730562
4
+ data.tar.gz: 86bfd58ddc3e941d344ea0ccb83ae608305ba86e5118243e19e47d9e306f1a20
5
5
  SHA512:
6
- metadata.gz: b9b16ea951a97dd3577962c54303ec46ab1e3c9df2bd890408a925a69f65f71a555139facefca207c32f87d82bf8a4984e20711a95c0de807fa085c2a1ec9dca
7
- data.tar.gz: d94abe5413f90b4a7cac2fcf875f834d6066904e0b2b36f3b3991a9123d89be19a19bd6b8484962a6ecf082b3c84bbab45bb06a825287498c12cc9aa41fdbd26
6
+ metadata.gz: 47d07d1d36a509892ee5cc4e05794233ef6d37c6f866896133a89abc92a0ed5af30dc2c1a7640925b71ff2f0dba5c52d378c66e3926d9c85cf5249df87ea663a
7
+ data.tar.gz: a8e56a738b7afc220129eb7bd7dd5762b10a8a8cf09285327917a83e68b2b167ee18725c903c2a232b4f4b67c16849aae64e9937817a11513ff9548d4a0a6bbb
data/README.md CHANGED
@@ -1,12 +1,88 @@
1
- # master-crypt
1
+ # Master Crypt
2
+
3
+ [![CircleCI](https://circleci.com/gh/cianmce/master-crypt.svg?style=shield)](https://circleci.com/gh/cianmce/master-crypt)
4
+
5
+ Master Key is a gem for encrypting data with a [master keying](https://en.wikipedia.org/wiki/Master_keying) approach
6
+
7
+ This allows you to have a master key to decrypt the full set of data while also creating keys that can only decrypt a subset of data. These keys can then be safely distributed to relevant actors who will be only able to access their permitted data
8
+
9
+ You can encrypt data with as many keys as needed, all of which will be able to decrypt the data while only causing a small encrypted data size increase of 129 bytes for each extra key
10
+
11
+
12
+ ## Installatio
13
+ ### Installing RbNaCl
14
+ https://github.com/RubyCrypto/rbnacl#installation
15
+
16
+ #### OS X users
17
+ ```sh
18
+ brew install libsodium
19
+ ```
20
+
21
+ #### FreeBSD users
22
+ ```sh
23
+ pkg install libsodium
24
+ ```
25
+
26
+ #### APT users
27
+
28
+ ```sh
29
+ apt install libsodium-dev
30
+ ```
31
+
32
+ ### Installing MasterCrypt
33
+ ```sh
34
+ gem install master_crypt
35
+ ```
36
+
37
+ ## Usage
38
+ ### Encrypting data with a master key
39
+ ```ruby
40
+ require "master_crypt"
41
+
42
+ master_key = "Very secure & random master k3y"
43
+ other_secret_key = "Another very secure & random other k3y"
44
+ plaintext = "Secret data..."
45
+ master_crypt = MasterCrypt.new(master_key)
46
+
47
+ encrypted_data = master_crypt.master_key_encrypt(plaintext, [other_secret_key])
48
+ # encrypted_data can be decrypted with either the master_key or other_secret_key
49
+ ```
50
+
51
+ ### Decrypting data with a master key
52
+ ```ruby
53
+ master_key = "Very secure & random master k3y"
54
+ encrypted_data = "...."
55
+ master_crypt = MasterCrypt.new(master_key)
56
+
57
+ plaintext = master_crypt.master_key_decrypt(encrypted_data)
58
+ ```
59
+
60
+ ### Encrypting data with an array of keys
61
+
62
+ ```ruby
63
+ secret_keys = ["array", "of", "secret", "keys"]
64
+ encrypted_data = MasterCrypt.encrypt(plaintext, secret_keys)
65
+ ```
66
+
67
+ ### Decrypting data with a specific key
68
+
69
+ ```ruby
70
+ MasterCrypt.decrypt(encrypted_data, secret_keys[0])
71
+ ```
2
72
 
3
73
  ## Development
4
74
  ```sh
5
75
  bundle install
6
76
  ```
7
77
 
8
- ### Specs
9
- Run a
78
+ ### Run all specs + standardrb
79
+
10
80
  ```sh
81
+ bundle exec rake
82
+ ```
11
83
 
84
+ ### Run specs using guard
85
+
86
+ ```sh
87
+ bundle exec guard
12
88
  ```
data/lib/master_crypt.rb CHANGED
@@ -3,11 +3,59 @@ require "rbnacl"
3
3
  require "base64"
4
4
  require "digest"
5
5
 
6
- module MasterCrypt
6
+ class MasterCrypt
7
+ class CryptoError < StandardError; end
8
+
9
+ # Create a new MasterCrypt object with a master key which
10
+ # is used in `master_key_encrypt` and `master_key_decrypt`
11
+ #
12
+ # @param [String] Master key
13
+ #
14
+ # @return [MasterCrypt] A MasterCrypt object with a stored master key
15
+ def initialize(master_key)
16
+ raise ArgumentError, "Master key must not be blank" if master_key.nil? || master_key.empty?
17
+ @master_key = master_key
18
+ end
19
+
20
+ # Encrypts plaintext data with the master key and an optional
21
+ # list of additional secret keys
22
+ #
23
+ # @param plaintext [String] Plaintext data to be encrypted
24
+ # @param secret_keys [Array<String>] Optional list of
25
+ # additional secret keys to be used for encrypting data
26
+ #
27
+ # @return [String] Base64 representation of encrypted data
28
+ #
29
+ # @raise [ArgumentError] When secret keys are missing or blank
30
+ def master_key_encrypt(plaintext, secret_keys = [])
31
+ self.class.encrypt(plaintext, [@master_key] + Array(secret_keys))
32
+ end
33
+
34
+ # Decrypts encrypted data with the master key
35
+ #
36
+ # @param encrypted_data [String] Base64 representation of encrypted data
37
+ #
38
+ # @return [String] Decrypted plaintext data
39
+ #
40
+ # @raise [MasterCrypt::CryptoError] When master key or encrypted data is invalid
41
+ def master_key_decrypt(encrypted_data)
42
+ self.class.decrypt(encrypted_data, @master_key)
43
+ end
44
+
7
45
  class << self
8
- def encrypt(plaintext, secrets)
9
- raise "Secrets must not be blank" unless secrets.select(&:empty?).empty?
10
- raise "At least 1 secret is required" if !secrets.is_a?(Array) || secrets.empty?
46
+ # Encrypts plaintext data with a list of secret keys
47
+ #
48
+ # @param plaintext [String] Plaintext data to be encrypted
49
+ # @param secret_keys [Array<String>] A list of secret keys to be used for encrypting data
50
+ #
51
+ # @return [String] Base64 representation of encrypted data
52
+ #
53
+ # @raise [ArgumentError] When secret keys are missing or blank
54
+ def encrypt(plaintext, secret_keys)
55
+ raise ArgumentError, "At least 1 secret key is required" if !secret_keys.is_a?(Array) || secret_keys.empty?
56
+ raise ArgumentError, "Secret keys must not be blank" unless secret_keys.select(&:empty?).empty?
57
+ # there's no point in using the same key multiple times
58
+ secret_keys.uniq!
11
59
 
12
60
  random_key = RbNaCl::Random.random_bytes(RbNaCl::SecretBox.key_bytes)
13
61
  # encrypt data with random_key
@@ -17,7 +65,7 @@ module MasterCrypt
17
65
  encrypted_data64 = Base64.strict_encode64(encrypted_data)
18
66
 
19
67
  # encrypt random_kets with each secret
20
- encrypted_random_keys64 = secrets.collect do |secret|
68
+ encrypted_random_keys64 = secret_keys.collect do |secret|
21
69
  key = generate_key_from_secret(secret)
22
70
  box = RbNaCl::SimpleBox.from_secret_key(key)
23
71
 
@@ -29,16 +77,26 @@ module MasterCrypt
29
77
  Base64.strict_encode64(encrypted_data64 + "|" + encrypted_random_keys64.join(":"))
30
78
  end
31
79
 
32
- def decrypt(encrypted_data, secret)
80
+ # Decrypts encrypted data with a provided secret key
81
+ #
82
+ # @param encrypted_data [String] Base64 representation of encrypted data
83
+ # @param secret_key [String] Secret key to be used to decrypt data
84
+ #
85
+ # @return [String] Decrypted plaintext data
86
+ #
87
+ # @raise [MasterCrypt::CryptoError] When secret key or encrypted data is invalid
88
+ def decrypt(encrypted_data, secret_key)
33
89
  encrypted_data64, encrypted_random_keys64_joined = Base64.strict_decode64(encrypted_data).split("|", 2)
34
90
 
35
91
  encrypted_random_keys64 = encrypted_random_keys64_joined.split(":")
36
- key = find_key(encrypted_random_keys64, secret)
92
+ key = find_key(encrypted_random_keys64, secret_key)
37
93
 
38
94
  box = RbNaCl::SimpleBox.from_secret_key(key)
39
95
 
40
96
  ciphertext = Base64.strict_decode64(encrypted_data64)
41
97
  box.decrypt(ciphertext).force_encoding(Encoding::UTF_8)
98
+ rescue RbNaCl::CryptoError => e
99
+ raise CryptoError, e.message
42
100
  end
43
101
 
44
102
  private
@@ -55,7 +113,7 @@ module MasterCrypt
55
113
  rescue RbNaCl::CryptoError
56
114
  end
57
115
  end
58
- raise "No valid key for '#{secret}'"
116
+ raise CryptoError, "Invalid secret key '#{secret}'"
59
117
  end
60
118
 
61
119
  def generate_key_from_secret(secret)
@@ -1,3 +1,3 @@
1
- module MasterCrypt
2
- VERSION = "0.0.1"
1
+ class MasterCrypt
2
+ VERSION = "0.0.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: master-crypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cian McElhinney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-01 00:00:00.000000000 Z
11
+ date: 2021-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standardrb
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '2.2'
33
+ version: '1'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '2.2'
40
+ version: '1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -70,86 +70,86 @@ dependencies:
70
70
  name: pry
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: 0.13.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 0.13.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: pry-byebug
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '3.9'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '3.9'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: pry-doc
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '1.1'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '1.1'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: guard
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ">="
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: '2.18'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ">="
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: '2.18'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: guard-rspec
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ">="
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '0'
131
+ version: 4.7.3
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ">="
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '0'
138
+ version: 4.7.3
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rbnacl
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '='
143
+ - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 7.1.1
145
+ version: '7.0'
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - '='
150
+ - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 7.1.1
152
+ version: '7.0'
153
153
  description: Allows for encrypting a single piece of data with multiple keys which
154
154
  can each be used to decrypt it
155
155
  email:
@@ -176,7 +176,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - ">="
178
178
  - !ruby/object:Gem::Version
179
- version: '0'
179
+ version: 2.3.0
180
180
  required_rubygems_version: !ruby/object:Gem::Requirement
181
181
  requirements:
182
182
  - - ">="