Module: Vidibus::Secure
- Defined in:
- lib/vidibus/secure.rb,
lib/vidibus/secure/mongoid.rb,
lib/vidibus/secure/version.rb,
lib/vidibus/secure/extensions/controller.rb
Defined Under Namespace
Modules: Extensions, Mongoid Classes: DecryptError, Error, InputError, KeyError
Constant Summary collapse
- GCM_VERSION =
0x02- CBC_VERSION =
0x01- GCM_IV_LEN =
12- GCM_TAG_LEN =
16- VERSION =
'5.0.0'
Class Attribute Summary collapse
-
.key_resolver ⇒ Object
Returns the value of attribute key_resolver.
Class Method Summary collapse
-
.current_key ⇒ Object
Returns the key to use for Mongoid attr_encrypted.
-
.decrypt(data, key, options = {}) ⇒ Object
Decrypts given data with given key.
-
.encrypt(data, key, options = {}) ⇒ Object
Encrypts given data with given key (AES-256-GCM).
-
.legacy_decrypt(data, key, options = {}) ⇒ Object
Decrypts a v4 (CBC) ciphertext, forcing the legacy path.
-
.random(options = {}) ⇒ Object
Returns a truly random string.
-
.settings ⇒ Object
Define default settings for random, sign, and crypt.
-
.sign(data, key, options = {}) ⇒ Object
Returns signature of given data with given key.
-
.sign_request(verb, path, params, key, signature_param = nil) ⇒ Object
Signs request.
-
.verify_request(verb, path, params, key, signature_param = nil) ⇒ Object
Verifies that given request is valid.
Class Attribute Details
.key_resolver ⇒ Object
Returns the value of attribute key_resolver.
16 17 18 |
# File 'lib/vidibus/secure.rb', line 16 def key_resolver @key_resolver end |
Class Method Details
.current_key ⇒ Object
Returns the key to use for Mongoid attr_encrypted. Resolver wins over ENV; raises if neither is set.
20 21 22 23 24 25 26 27 |
# File 'lib/vidibus/secure.rb', line 20 def current_key resolved = key_resolver&.call return resolved if resolved return ENV['VIDIBUS_SECURE_KEY'] if ENV['VIDIBUS_SECURE_KEY'] raise KeyError, 'No encryption key — set Vidibus::Secure.key_resolver ' \ 'or ENV["VIDIBUS_SECURE_KEY"]' end |
.decrypt(data, key, options = {}) ⇒ Object
Decrypts given data with given key. Dispatches on the version byte (0x02 GCM, 0x01 legacy CBC) and falls back to bare CBC (v4 layout) when no version byte is present.
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/vidibus/secure.rb', line 74 def decrypt(data, key, = {}) unless key raise KeyError.new( 'Please provide a secret key to decrypt data with.' ) end return data if data.nil? || data == '' = settings[:crypt].merge() raw = decode(data, ) plaintext = dispatch_decrypt(raw, key) return data unless plaintext begin JSON.parse(plaintext) rescue JSON::ParserError plaintext end end |
.encrypt(data, key, options = {}) ⇒ Object
Encrypts given data with given key (AES-256-GCM).
59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/vidibus/secure.rb', line 59 def encrypt(data, key, = {}) unless key raise KeyError.new( 'Please provide a secret key to encrypt data with.' ) end = settings[:crypt].merge() data = JSON.generate(data) unless data.is_a?(String) blob = gcm_encrypt(data, derive_key(key)) encode(blob, ) end |
.legacy_decrypt(data, key, options = {}) ⇒ Object
Decrypts a v4 (CBC) ciphertext, forcing the legacy path. Use this only for the rare case where a v4 blob’s first byte happens to be 0x01 or 0x02 and would otherwise be misrouted. The blob may carry a 0x01 version byte preamble or be bare base64/hex.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/vidibus/secure.rb', line 97 def legacy_decrypt(data, key, = {}) unless key raise KeyError.new( 'Please provide a secret key to decrypt data with.' ) end return data if data.nil? || data == '' = settings[:crypt].merge() raw = decode(data, ) return nil unless raw && raw != '' ct = raw.getbyte(0) == CBC_VERSION ? raw.byteslice(1, raw.bytesize - 1) : raw plaintext = cbc_decrypt(ct, key) begin JSON.parse(plaintext) rescue JSON::ParserError plaintext end end |
.random(options = {}) ⇒ Object
Returns a truly random string.
39 40 41 42 43 |
# File 'lib/vidibus/secure.rb', line 39 def random( = {}) = settings[:random].merge() length = [:length] SecureRandom.send([:encoding], length)[0, length] end |
.settings ⇒ Object
Define default settings for random, sign, and crypt.
30 31 32 33 34 35 36 |
# File 'lib/vidibus/secure.rb', line 30 def settings @settings ||= { random: { length: 50, encoding: :base64 }, sign: { algorithm: 'SHA256', encoding: :hex }, crypt: { algorithm: 'AES-256-GCM', encoding: :base64 } } end |
.sign(data, key, options = {}) ⇒ Object
Returns signature of given data with given key.
46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/vidibus/secure.rb', line 46 def sign(data, key, = {}) unless key raise KeyError.new( 'Please provide a secret key to sign data with.' ) end = settings[:sign].merge() digest = OpenSSL::Digest.new([:algorithm]) signature = OpenSSL::HMAC.digest(digest, key, data) encode(signature, ) end |
.sign_request(verb, path, params, key, signature_param = nil) ⇒ Object
Signs request.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/vidibus/secure.rb', line 118 def sign_request(verb, path, params, key, signature_param = nil) default_signature_param = :sign params_given = !!params if params_given && !params.is_a?(Hash) raise InputError.new('Given params is not a Hash.') end params = {} unless params_given signature_param ||= if params_given && params.keys.first.is_a?(String) default_signature_param.to_s else default_signature_param end uri = URI.parse(path) path_params = Rack::Utils.parse_nested_query(uri.query) uri.query = nil _verb = verb.to_s.downcase _params = params.merge(path_params). except(signature_param.to_s, signature_param.to_s.to_sym) signature_string = [ _verb, uri.to_s.gsub(/\/+$/, ''), _params.any? ? params_identifier(_params) : '' ].join('|') signature = sign(signature_string, key) if %w[post put].include?(_verb) || (params_given && path_params.empty?) params[signature_param] = signature else unless path.gsub!(/(#{signature_param}=)[^&]+/, "\\1#{signature}") glue = path.match(/\?/) ? '&' : '?' path << "#{glue}#{signature_param}=#{signature}" end end [path, params] end |
.verify_request(verb, path, params, key, signature_param = nil) ⇒ Object
Verifies that given request is valid.
162 163 164 165 166 167 168 |
# File 'lib/vidibus/secure.rb', line 162 def verify_request(verb, path, params, key, signature_param = nil) params ||= {} _path = path.dup _params = params.dup sign_request(verb, _path, _params, key, signature_param) path == _path && params == _params end |