ribbon-encrypted_store 0.1.5 → 0.2.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: 1d3aaf094d554be5178e1d81b38408165cd02e88
4
- data.tar.gz: 65fd270a315e816a1090f080b80ba9c5dbea421c
3
+ metadata.gz: 2ed9c1b5768713771553fc0ae858ba9230f12e7a
4
+ data.tar.gz: 4ca77eb35ee661056d33ad308f9a6132b7ea94d6
5
5
  SHA512:
6
- metadata.gz: 393874c9a5123284c259e83191b20ae9307bddcee2743f8d446a6bb01b864d68165c0c9beb7f2763b0e0ebe205464c823a0d22d43dd992e141ba315ae68b04eb
7
- data.tar.gz: ef0d1e2e453110e96310beb44b0e1d3caedbd87e99ea3b2cc41be99201e8ea7341e07f17c1d8f1cf1847680c0cd0eec3afac6e85206aab8cc650811edf9df66e
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
- def encrypt(dek, salt)
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::SaltTooBigError if salt.bytes.length > 255
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 = _encrypted_data_header(salt) + encryptor.update(self.to_json) + encryptor.final
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
- digest = OpenSSL::Digest::SHA256.new
52
- key_and_iv = OpenSSL::PKCS5.pbkdf2_hmac(key, salt, 4096, 48, digest)
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
- key = key_and_iv[0..31]
55
- iv = key_and_iv[32..-1]
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 = bytes[0]
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 _encrypted_data_header(salt)
124
+ def _encrypted_data_header_v1(salt)
92
125
  "\x01" + salt.bytes.length.chr + salt
93
126
  end
94
127
 
95
- def _keyiv_gen(key, salt)
96
- self.class._keyiv_gen(key, salt)
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 SaltTooBigError < CryptoHashError; end
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(_decrypted_key, EncryptionKeySalt.generate_salt(_encryption_key_id))
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
@@ -1,5 +1,5 @@
1
1
  module Ribbon
2
2
  module EncryptedStore
3
- VERSION = '0.1.5'
3
+ VERSION = '0.2.0'
4
4
  end # EncryptedStore
5
5
  end # Ribbon
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.1.5
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-07-24 00:00:00.000000000 Z
12
+ date: 2015-10-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bcrypt