ribbon-encrypted_store 0.1.5 → 0.2.0
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
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ed9c1b5768713771553fc0ae858ba9230f12e7a
|
4
|
+
data.tar.gz: 4ca77eb35ee661056d33ad308f9a6132b7ea94d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1abc59705a77c7d009823b388681a4e004a472308b6885012e6af6b59b65deeabc09daeddf56594e30affb21de333679bbf7cf84c4157b79d981acb0fa399551
|
7
|
+
data.tar.gz: b626cd351cdffbb155cebdc9c43fc30fed4f6e18c630e32c91ef4106a88ce289e325e5a04f62e9ee40f7784a3ca12d06a1adde53c614ed7bf61c9c5b75cd40bb
|
@@ -11,32 +11,31 @@ module Ribbon::EncryptedStore
|
|
11
11
|
|
12
12
|
##
|
13
13
|
# Encrypts the hash using the data encryption key and salt.
|
14
|
-
# Returns a blob:
|
15
|
-
#
|
16
|
-
# | Byte 0 | Byte 1 | Bytes 2...S | Bytes S+1...E | Bytes E+1..E+4 |
|
17
|
-
# --------------------------------------------------------------------------
|
18
|
-
# | Version | Salt Length | Salt | Encrypted Data | CRC32 |
|
19
14
|
#
|
20
|
-
|
15
|
+
# Returns a blob:
|
16
|
+
# | Byte 0 | Byte 1 | Byte 2 | Bytes 3...S | Bytes S+1...E | Bytes E+1..E+4 |
|
17
|
+
# ------------------------------------------------------------------------------------------------
|
18
|
+
# | Version | Salt Length | Iteration Magnitude | Salt | Encrypted Data | CRC32 |
|
19
|
+
def encrypt(dek, salt, iter_mag=10)
|
21
20
|
return nil if empty?
|
22
|
-
raise Errors::
|
21
|
+
raise Errors::InvalidSaltSize, 'too long' if salt.bytes.length > 255
|
23
22
|
|
24
|
-
key, iv = _keyiv_gen(dek, salt)
|
23
|
+
key, iv = _keyiv_gen(dek, salt, iter_mag)
|
25
24
|
|
26
25
|
encryptor = OpenSSL::Cipher::AES256.new(:CBC).encrypt
|
27
26
|
encryptor.key = key
|
28
27
|
encryptor.iv = iv
|
29
28
|
|
30
|
-
data_packet =
|
29
|
+
data_packet = _encrypted_data_header_v2(salt, iter_mag) + encryptor.update(self.to_json) + encryptor.final
|
31
30
|
_append_crc32(data_packet)
|
32
31
|
end
|
33
32
|
|
34
33
|
class << self
|
35
34
|
def decrypt(dek, data)
|
36
35
|
return CryptoHash.new unless data
|
37
|
-
salt, data = _split_binary_data(data)
|
36
|
+
salt, iter_mag, data = _split_binary_data(data)
|
38
37
|
|
39
|
-
key, iv = _keyiv_gen(dek, salt)
|
38
|
+
key, iv = _keyiv_gen(dek, salt, iter_mag)
|
40
39
|
|
41
40
|
decryptor = OpenSSL::Cipher::AES256.new(:CBC).decrypt
|
42
41
|
decryptor.key = key
|
@@ -47,12 +46,18 @@ module Ribbon::EncryptedStore
|
|
47
46
|
CryptoHash.new(new_hash)
|
48
47
|
end
|
49
48
|
|
50
|
-
def _keyiv_gen(key, salt)
|
51
|
-
|
52
|
-
|
49
|
+
def _keyiv_gen(key, salt, iter_mag)
|
50
|
+
if iter_mag == -1
|
51
|
+
raise Errors::InvalidKeySize, 'must be exactly 256 bits' unless key.bytes.length == 32
|
52
|
+
raise Errors::InvalidSaltSize, 'must be exactly 128 bits' unless salt.bytes.length == 16
|
53
|
+
iv = salt
|
54
|
+
else
|
55
|
+
digest = OpenSSL::Digest::SHA256.new
|
56
|
+
key_and_iv = OpenSSL::PKCS5.pbkdf2_hmac(key, salt, 1 << iter_mag, 48, digest)
|
53
57
|
|
54
|
-
|
55
|
-
|
58
|
+
key = key_and_iv[0..31]
|
59
|
+
iv = key_and_iv[32..-1]
|
60
|
+
end
|
56
61
|
|
57
62
|
[key, iv]
|
58
63
|
end
|
@@ -61,7 +66,18 @@ module Ribbon::EncryptedStore
|
|
61
66
|
# Split encrypted data and CRC
|
62
67
|
bytes = encrypted_data.bytes
|
63
68
|
|
64
|
-
version
|
69
|
+
version = bytes[0]
|
70
|
+
version_method = "_split_binary_data_v#{version}"
|
71
|
+
|
72
|
+
if respond_to?(version_method)
|
73
|
+
send(version_method, encrypted_data)
|
74
|
+
else
|
75
|
+
raise Errors::UnsupportedVersionError, "Unsupported encrypted data version: #{version}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def _split_binary_data_v1(encrypted_data)
|
80
|
+
bytes = encrypted_data.bytes
|
65
81
|
salt_length = bytes[1]
|
66
82
|
|
67
83
|
salt_start_index = 2
|
@@ -72,9 +88,26 @@ module Ribbon::EncryptedStore
|
|
72
88
|
crc = bytes[-4..-1]
|
73
89
|
raise Errors::ChecksumFailedError unless crc == _calc_crc32(encrypted_data[0..-5]).bytes
|
74
90
|
|
75
|
-
[salt, data]
|
91
|
+
[salt, 12, data]
|
92
|
+
end
|
93
|
+
|
94
|
+
def _split_binary_data_v2(encrypted_data)
|
95
|
+
bytes = encrypted_data.bytes
|
96
|
+
salt_length = bytes[1]
|
97
|
+
iter_mag = bytes[2].chr.unpack('c').first
|
98
|
+
|
99
|
+
salt_start_index = 3
|
100
|
+
salt_end_index = salt_start_index + salt_length - 1
|
101
|
+
salt = bytes[salt_start_index..salt_end_index].pack('c*')
|
102
|
+
data = bytes[salt_end_index+1..-5].pack('c*')
|
103
|
+
|
104
|
+
crc = bytes[-4..-1]
|
105
|
+
raise Errors::ChecksumFailedError unless crc == _calc_crc32(encrypted_data[0..-5]).bytes
|
106
|
+
|
107
|
+
[salt, iter_mag, data]
|
76
108
|
end
|
77
109
|
|
110
|
+
|
78
111
|
def _calc_crc32(data)
|
79
112
|
[Zlib.crc32(data)].pack('N')
|
80
113
|
end
|
@@ -83,17 +116,27 @@ module Ribbon::EncryptedStore
|
|
83
116
|
private
|
84
117
|
|
85
118
|
##
|
86
|
-
# Generates the encrypted data header:
|
119
|
+
# Generates the version 1 encrypted data header:
|
87
120
|
# | Byte 0 | Byte 1 | Bytes 2...S
|
88
121
|
# ---------------------------------------------------
|
89
122
|
# | Version | Salt Length | Salt
|
90
123
|
#
|
91
|
-
def
|
124
|
+
def _encrypted_data_header_v1(salt)
|
92
125
|
"\x01" + salt.bytes.length.chr + salt
|
93
126
|
end
|
94
127
|
|
95
|
-
|
96
|
-
|
128
|
+
##
|
129
|
+
# Generates the version 2 encrypted data header:
|
130
|
+
# | Byte 0 | Byte 1 | Byte 2 | Bytes 3...S
|
131
|
+
# ----------------------------------------------------------------------
|
132
|
+
# | Version | Salt Length | Iteration Magnitude | Salt
|
133
|
+
#
|
134
|
+
def _encrypted_data_header_v2(salt, iter_mag)
|
135
|
+
"\x02" + salt.bytes.length.chr + [iter_mag].pack('c') + salt
|
136
|
+
end
|
137
|
+
|
138
|
+
def _keyiv_gen(key, salt, iter_mag)
|
139
|
+
self.class._keyiv_gen(key, salt, iter_mag)
|
97
140
|
end
|
98
141
|
|
99
142
|
def _append_crc32(data)
|
@@ -9,6 +9,8 @@ module Ribbon::EncryptedStore
|
|
9
9
|
# CryptoHash Errors
|
10
10
|
class CryptoHashError < Error; end
|
11
11
|
class ChecksumFailedError < CryptoHashError; end
|
12
|
-
class
|
12
|
+
class InvalidSaltSize < CryptoHashError; end
|
13
|
+
class InvalidKeySize < CryptoHashError; end
|
14
|
+
class UnsupportedVersionError < CryptoHashError; end
|
13
15
|
end # Errors
|
14
|
-
end # Ribbon::EncryptedStore
|
16
|
+
end # Ribbon::EncryptedStore
|
@@ -35,7 +35,7 @@ module Ribbon::EncryptedStore
|
|
35
35
|
|
36
36
|
def attr_encrypted(*args)
|
37
37
|
# Store attrs in class data
|
38
|
-
_encrypted_store_data[:encrypted_attributes] = args
|
38
|
+
_encrypted_store_data[:encrypted_attributes] = args.map(&:to_sym)
|
39
39
|
|
40
40
|
args.each { |arg|
|
41
41
|
define_method(arg) { _encrypted_store_get(arg) }
|
@@ -83,7 +83,7 @@ module Ribbon::EncryptedStore
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def _encrypted_store_save
|
86
|
-
if !(self.changed & _encrypted_store_data[:encrypted_attributes]).empty? || @_reencrypting
|
86
|
+
if !(self.changed.map(&:to_sym) & _encrypted_store_data[:encrypted_attributes]).empty? || @_reencrypting
|
87
87
|
# Obtain a lock without overriding attribute values for this record.
|
88
88
|
record = self.class.unscoped { self.class.lock.find(id) } unless new_record?
|
89
89
|
|
@@ -91,8 +91,16 @@ module Ribbon::EncryptedStore
|
|
91
91
|
self.encryption_key_id = record.encryption_key_id if record && record.encryption_key_id
|
92
92
|
end
|
93
93
|
|
94
|
+
iter_mag = Ribbon::EncryptedStore.config.iteration_magnitude? ?
|
95
|
+
Ribbon::EncryptedStore.config.iteration_magnitude :
|
96
|
+
-1
|
97
|
+
|
94
98
|
@_reencrypting = false
|
95
|
-
self.encrypted_store = _crypto_hash.encrypt(
|
99
|
+
self.encrypted_store = _crypto_hash.encrypt(
|
100
|
+
_decrypted_key,
|
101
|
+
EncryptionKeySalt.generate_salt(_encryption_key_id),
|
102
|
+
iter_mag
|
103
|
+
)
|
96
104
|
end
|
97
105
|
end
|
98
106
|
end # ActiveRecordMixin
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ribbon-encrypted_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Honer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-10-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bcrypt
|