Class: Sequel::Plugins::ColumnEncryption::Cryptor
- Defined in:
- lib/sequel/plugins/column_encryption.rb
Overview
Cryptor handles the encryption and decryption of rows for a key set. It also provides methods that return search prefixes, which datasets use in queries.
The same cryptor can support non-searchable, searchable, and case-insensitive searchable columns.
Constant Summary collapse
- NOT_SEARCHABLE =
Flags
0
- SEARCHABLE =
1
- LOWERCASE_SEARCHABLE =
2
- DEFAULT_PADDING =
This is the default padding, but up to 2x the padding can be used for a record.
8
Instance Method Summary collapse
-
#case_insensitive_searchable_encrypt(data) ⇒ Object
Encrypt in case insensitive searchable format with the first configured encryption key.
-
#current_key_prefix(search_type) ⇒ Object
The prefix string of columns for the given search type and the first configured encryption key.
-
#decrypt(data) ⇒ Object
Decrypt using any supported format and any available key.
-
#encrypt(data) ⇒ Object
Encrypt in not searchable format with the first configured encryption key.
-
#initialize(keys) ⇒ Cryptor
constructor
Keys should be an array of arrays containing key_id, key string, auth_data, and padding.
-
#lowercase_search_prefixes(data) ⇒ Object
The prefix values to search for the given data (an array of strings), assuming the column uses the case insensitive searchable format.
-
#regular_and_lowercase_search_prefixes(data) ⇒ Object
The prefix values to search for the given data (an array of strings), assuming the column uses either the searchable or the case insensitive searchable format.
-
#search_prefixes(data) ⇒ Object
The prefix values to search for the given data (an array of strings), assuming the column uses the searchable format.
-
#searchable_encrypt(data) ⇒ Object
Encrypt in searchable format with the first configured encryption key.
Constructor Details
#initialize(keys) ⇒ Cryptor
Keys should be an array of arrays containing key_id, key string, auth_data, and padding.
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/sequel/plugins/column_encryption.rb', line 357 def initialize(keys) if !keys || keys.empty? raise Error, "Cannot initialize encryptor without encryption key" end # First key is used for encryption @key_id, @key, @auth_data, @padding = keys[0] # All keys are candidates for decryption @key_map = {} keys.each do |key_id, key, auth_data, padding| @key_map[key_id] = [key, auth_data, padding].freeze end freeze end |
Instance Method Details
#case_insensitive_searchable_encrypt(data) ⇒ Object
Encrypt in case insensitive searchable format with the first configured encryption key.
443 444 445 |
# File 'lib/sequel/plugins/column_encryption.rb', line 443 def case_insensitive_searchable_encrypt(data) _encrypt(data, _search_prefix(data.downcase, LOWERCASE_SEARCHABLE, @key_id, @key)) end |
#current_key_prefix(search_type) ⇒ Object
The prefix string of columns for the given search type and the first configured encryption key. Used to find values that do not use this prefix in order to perform reencryption.
449 450 451 |
# File 'lib/sequel/plugins/column_encryption.rb', line 449 def current_key_prefix(search_type) urlsafe_encode64("#{search_type.chr}\0#{@key_id.chr}") end |
#decrypt(data) ⇒ Object
Decrypt using any supported format and any available key.
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/sequel/plugins/column_encryption.rb', line 375 def decrypt(data) begin data = urlsafe_decode64(data) rescue ArgumentError raise Error, "Unable to decode encrypted column: invalid base64" end unless data.getbyte(1) == 0 && data.getbyte(3) == 0 raise Error, "Unable to decode encrypted column: invalid format" end flags = data.getbyte(0) key, auth_data = @key_map[data.getbyte(2)] unless key raise Error, "Unable to decode encrypted column: invalid key id" end case flags when NOT_SEARCHABLE if data.bytesize < 65 raise Error, "Decoded encrypted column smaller than minimum size" end data.slice!(0, 4) when SEARCHABLE, LOWERCASE_SEARCHABLE if data.bytesize < 97 raise Error, "Decoded encrypted column smaller than minimum size" end data.slice!(0, 36) else raise Error, "Unable to decode encrypted column: invalid flags" end key_part = data.slice!(0, 32) cipher_iv = data.slice!(0, 12) auth_tag = data.slice!(0, 16) cipher = OpenSSL::Cipher.new("aes-256-gcm") cipher.decrypt cipher.iv = cipher_iv cipher.key = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, key, key_part) cipher.auth_data = auth_data cipher.auth_tag = auth_tag begin decrypted_data = cipher.update(data) << cipher.final rescue OpenSSL::Cipher::CipherError => e raise Error, "Unable to decrypt encrypted column: #{e.class} (probably due to encryption key or auth data mismatch or corrupt data)" end # Remove padding decrypted_data.slice!(0, decrypted_data.getbyte(0) + 1) decrypted_data end |
#encrypt(data) ⇒ Object
Encrypt in not searchable format with the first configured encryption key.
433 434 435 |
# File 'lib/sequel/plugins/column_encryption.rb', line 433 def encrypt(data) _encrypt(data, "#{NOT_SEARCHABLE.chr}\0#{@key_id.chr}\0") end |
#lowercase_search_prefixes(data) ⇒ Object
The prefix values to search for the given data (an array of strings), assuming the column uses the case insensitive searchable format.
461 462 463 |
# File 'lib/sequel/plugins/column_encryption.rb', line 461 def lowercase_search_prefixes(data) _search_prefixes(data.downcase, LOWERCASE_SEARCHABLE) end |
#regular_and_lowercase_search_prefixes(data) ⇒ Object
The prefix values to search for the given data (an array of strings), assuming the column uses either the searchable or the case insensitive searchable format. Should be used only when transitioning between formats (used by the :search_both option when encrypting columns).
468 469 470 |
# File 'lib/sequel/plugins/column_encryption.rb', line 468 def regular_and_lowercase_search_prefixes(data) search_prefixes(data) + lowercase_search_prefixes(data) end |
#search_prefixes(data) ⇒ Object
The prefix values to search for the given data (an array of strings), assuming the column uses the searchable format.
455 456 457 |
# File 'lib/sequel/plugins/column_encryption.rb', line 455 def search_prefixes(data) _search_prefixes(data, SEARCHABLE) end |
#searchable_encrypt(data) ⇒ Object
Encrypt in searchable format with the first configured encryption key.
438 439 440 |
# File 'lib/sequel/plugins/column_encryption.rb', line 438 def searchable_encrypt(data) _encrypt(data, _search_prefix(data, SEARCHABLE, @key_id, @key)) end |