Class: EncryptedStore::CryptoHash
- Inherits:
-
Hash
- Object
- Hash
- EncryptedStore::CryptoHash
- Defined in:
- lib/encrypted_store/crypto_hash.rb
Class Method Summary collapse
- ._calc_crc32(data) ⇒ Object
- ._keyiv_gen(key, salt, iter_mag) ⇒ Object
- ._split_binary_data(encrypted_data) ⇒ Object
- ._split_binary_data_v1(encrypted_data) ⇒ Object
- ._split_binary_data_v2(encrypted_data) ⇒ Object
- .decrypt(dek, data) ⇒ Object
Instance Method Summary collapse
-
#encrypt(dek, salt, iter_mag = 10) ⇒ Object
Encrypts the hash using the data encryption key and salt.
-
#initialize(data = {}) ⇒ CryptoHash
constructor
A new instance of CryptoHash.
Constructor Details
#initialize(data = {}) ⇒ CryptoHash
7 8 9 10 |
# File 'lib/encrypted_store/crypto_hash.rb', line 7 def initialize(data={}) super() merge!(data) end |
Class Method Details
._calc_crc32(data) ⇒ Object
111 112 113 |
# File 'lib/encrypted_store/crypto_hash.rb', line 111 def _calc_crc32(data) [Zlib.crc32(data)].pack('N') end |
._keyiv_gen(key, salt, iter_mag) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/encrypted_store/crypto_hash.rb', line 49 def _keyiv_gen(key, salt, iter_mag) if iter_mag == -1 raise Errors::InvalidKeySize, 'must be exactly 256 bits' unless key.bytes.length == 32 raise Errors::InvalidSaltSize, 'must be exactly 128 bits' unless salt.bytes.length == 16 iv = salt else digest = OpenSSL::Digest::SHA256.new key_and_iv = OpenSSL::PKCS5.pbkdf2_hmac(key, salt, 1 << iter_mag, 48, digest) key = key_and_iv[0..31] iv = key_and_iv[32..-1] end [key, iv] end |
._split_binary_data(encrypted_data) ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/encrypted_store/crypto_hash.rb', line 65 def _split_binary_data(encrypted_data) # Split encrypted data and CRC bytes = encrypted_data.bytes version = bytes[0] version_method = "_split_binary_data_v#{version}" if respond_to?(version_method) send(version_method, encrypted_data) else raise Errors::UnsupportedVersionError, "Unsupported encrypted data version: #{version}" end end |
._split_binary_data_v1(encrypted_data) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/encrypted_store/crypto_hash.rb', line 79 def _split_binary_data_v1(encrypted_data) bytes = encrypted_data.bytes salt_length = bytes[1] salt_start_index = 2 salt_end_index = salt_start_index + salt_length - 1 salt = bytes[salt_start_index..salt_end_index].pack('c*') data = bytes[salt_end_index+1..-5].pack('c*') crc = bytes[-4..-1] raise Errors::ChecksumFailedError unless crc == _calc_crc32(encrypted_data[0..-5]).bytes [salt, 12, data] end |
._split_binary_data_v2(encrypted_data) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/encrypted_store/crypto_hash.rb', line 94 def _split_binary_data_v2(encrypted_data) bytes = encrypted_data.bytes salt_length = bytes[1] iter_mag = bytes[2].chr.unpack('c').first salt_start_index = 3 salt_end_index = salt_start_index + salt_length - 1 salt = bytes[salt_start_index..salt_end_index].pack('c*') data = bytes[salt_end_index+1..-5].pack('c*') crc = bytes[-4..-1] raise Errors::ChecksumFailedError unless crc == _calc_crc32(encrypted_data[0..-5]).bytes [salt, iter_mag, data] end |
.decrypt(dek, data) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/encrypted_store/crypto_hash.rb', line 34 def decrypt(dek, data) return CryptoHash.new unless data salt, iter_mag, data = _split_binary_data(data) key, iv = _keyiv_gen(dek, salt, iter_mag) decryptor = OpenSSL::Cipher::AES256.new(:CBC).decrypt decryptor.key = key decryptor.iv = iv new_hash = JSON.parse(decryptor.update(data) + decryptor.final) new_hash = Hash[new_hash.map { |k,v| [k.to_sym, v] }] CryptoHash.new(new_hash) end |
Instance Method Details
#encrypt(dek, salt, iter_mag = 10) ⇒ Object
Encrypts the hash using the data encryption key and salt.
Returns a blob: | Byte 0 | Byte 1 | Byte 2 | Bytes 3…S | Bytes S+1…E | Bytes E+1..E+4 |
| Version | Salt Length | Iteration Magnitude | Salt | Encrypted Data | CRC32 |
19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/encrypted_store/crypto_hash.rb', line 19 def encrypt(dek, salt, iter_mag=10) return nil if empty? raise Errors::InvalidSaltSize, 'too long' if salt.bytes.length > 255 key, iv = _keyiv_gen(dek, salt, iter_mag) encryptor = OpenSSL::Cipher::AES256.new(:CBC).encrypt encryptor.key = key encryptor.iv = iv data_packet = _encrypted_data_header_v2(salt, iter_mag) + encryptor.update(self.to_json) + encryptor.final _append_crc32(data_packet) end |