master-crypt 0.0.3 → 0.0.4
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/README.md +53 -7
- data/lib/master_crypt.rb +51 -6
- data/lib/master_crypt/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: feb8bc6283d255c63b665645b2380b97a424973674b68c5e43ca1148d2104539
|
4
|
+
data.tar.gz: a5d4a0bd894035a9b099936a910210010c5de652574bb90fd0bc6e2fa3080480
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb0ac83c13620f593102d8390376a692ef7a4a2fa8b4c7c8dd58da879d1b032cb3e9bf4821c28b72a115ca7ab8bb0de87b23c250d45b61ffb1feffa9c73281a4
|
7
|
+
data.tar.gz: 9da6ba87ab3b7eb58fc4be0e933d74d4fdbfc03c388cc7dd3508963eacefc044e52aa1c2ba6ef74ccbc95bca014ba107afe5a77d38b27b509aaebc6aae8954c9
|
data/README.md
CHANGED
@@ -1,15 +1,50 @@
|
|
1
|
-
#
|
1
|
+
# Master Crypt
|
2
2
|
|
3
|
-
|
3
|
+
[](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
|
+
```
|
4
36
|
|
37
|
+
## Usage
|
5
38
|
### Encrypting data with a master key
|
6
39
|
```ruby
|
40
|
+
require "master_crypt"
|
41
|
+
|
7
42
|
master_key = "Very secure & random master k3y"
|
8
|
-
other_secret_key = "Another very secure & random
|
9
|
-
|
43
|
+
other_secret_key = "Another very secure & random other k3y"
|
44
|
+
plaintext = "Secret data..."
|
10
45
|
master_crypt = MasterCrypt.new(master_key)
|
11
46
|
|
12
|
-
encrypted_data = master_crypt.master_key_encrypt(
|
47
|
+
encrypted_data = master_crypt.master_key_encrypt(plaintext, [other_secret_key])
|
13
48
|
# encrypted_data can be decrypted with either the master_key or other_secret_key
|
14
49
|
```
|
15
50
|
|
@@ -22,13 +57,24 @@ master_crypt = MasterCrypt.new(master_key)
|
|
22
57
|
plaintext = master_crypt.master_key_decrypt(encrypted_data)
|
23
58
|
```
|
24
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
|
+
```
|
72
|
+
|
25
73
|
## Development
|
26
74
|
```sh
|
27
75
|
bundle install
|
28
76
|
```
|
29
77
|
|
30
|
-
## Specs
|
31
|
-
|
32
78
|
### Run all specs + standardrb
|
33
79
|
|
34
80
|
```sh
|
data/lib/master_crypt.rb
CHANGED
@@ -4,23 +4,58 @@ require "base64"
|
|
4
4
|
require "digest"
|
5
5
|
|
6
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
|
7
15
|
def initialize(master_key)
|
8
|
-
raise "Master key must not be blank" if master_key.nil? || master_key.empty?
|
16
|
+
raise ArgumentError, "Master key must not be blank" if master_key.nil? || master_key.empty?
|
9
17
|
@master_key = master_key
|
10
18
|
end
|
11
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
|
12
30
|
def master_key_encrypt(plaintext, secret_keys = [])
|
13
31
|
self.class.encrypt(plaintext, [@master_key] + Array(secret_keys))
|
14
32
|
end
|
15
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
|
16
41
|
def master_key_decrypt(encrypted_data)
|
17
42
|
self.class.decrypt(encrypted_data, @master_key)
|
18
43
|
end
|
19
44
|
|
20
45
|
class << self
|
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
|
21
54
|
def encrypt(plaintext, secret_keys)
|
22
|
-
raise "At least 1 secret key is required" if !secret_keys.is_a?(Array) || secret_keys.empty?
|
23
|
-
raise "Secret keys must not be blank" unless secret_keys.select(&:empty?).empty?
|
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!
|
24
59
|
|
25
60
|
random_key = RbNaCl::Random.random_bytes(RbNaCl::SecretBox.key_bytes)
|
26
61
|
# encrypt data with random_key
|
@@ -42,16 +77,26 @@ class MasterCrypt
|
|
42
77
|
Base64.strict_encode64(encrypted_data64 + "|" + encrypted_random_keys64.join(":"))
|
43
78
|
end
|
44
79
|
|
45
|
-
|
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)
|
46
89
|
encrypted_data64, encrypted_random_keys64_joined = Base64.strict_decode64(encrypted_data).split("|", 2)
|
47
90
|
|
48
91
|
encrypted_random_keys64 = encrypted_random_keys64_joined.split(":")
|
49
|
-
key = find_key(encrypted_random_keys64,
|
92
|
+
key = find_key(encrypted_random_keys64, secret_key)
|
50
93
|
|
51
94
|
box = RbNaCl::SimpleBox.from_secret_key(key)
|
52
95
|
|
53
96
|
ciphertext = Base64.strict_decode64(encrypted_data64)
|
54
97
|
box.decrypt(ciphertext).force_encoding(Encoding::UTF_8)
|
98
|
+
rescue RbNaCl::CryptoError => e
|
99
|
+
raise CryptoError, e.message
|
55
100
|
end
|
56
101
|
|
57
102
|
private
|
@@ -68,7 +113,7 @@ class MasterCrypt
|
|
68
113
|
rescue RbNaCl::CryptoError
|
69
114
|
end
|
70
115
|
end
|
71
|
-
raise "
|
116
|
+
raise CryptoError, "Invalid secret key '#{secret}'"
|
72
117
|
end
|
73
118
|
|
74
119
|
def generate_key_from_secret(secret)
|
data/lib/master_crypt/version.rb
CHANGED
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.
|
4
|
+
version: 0.0.4
|
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-
|
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: '
|
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: '
|
40
|
+
version: '1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|